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 @@
1# Build directory 1# Build directory
2build/ 2build/
3doc-build/
3 4
4# Generated source files 5# Generated source files
5src/common/scm_rev.cpp 6src/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 @@
1[submodule "externals/inih/inih"]
2 path = externals/inih/inih
3 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)
68 if (NOT APPLE) 68 if (NOT APPLE)
69 find_package(X11 REQUIRED) 69 find_package(X11 REQUIRED)
70 endif() 70 endif()
71 71
72 find_package(PkgConfig REQUIRED) 72 find_package(PkgConfig REQUIRED)
73 pkg_search_module(GLFW REQUIRED glfw3) 73 pkg_search_module(GLFW REQUIRED glfw3)
74 endif() 74 endif()
@@ -127,6 +127,10 @@ get_git_head_revision(GIT_REF_SPEC GIT_REV)
127git_describe(GIT_DESC --always --long --dirty) 127git_describe(GIT_DESC --always --long --dirty)
128git_branch_name(GIT_BRANCH) 128git_branch_name(GIT_BRANCH)
129 129
130set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih")
131include_directories(${INI_PREFIX})
132add_subdirectory(${INI_PREFIX})
133
130# process subdirectories 134# process subdirectories
131if(ENABLE_QT) 135if(ENABLE_QT)
132 include_directories(externals/qhexedit) 136 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 @@
1# Doxyfile 1.8.8
2
3# This file describes the settings to be used by the documentation system
4# doxygen (www.doxygen.org) for a project.
5#
6# All text after a double hash (##) is considered a comment and is placed in
7# front of the TAG it is preceding.
8#
9# All text after a single hash (#) is considered a comment and will be ignored.
10# The format is:
11# TAG = value [value, ...]
12# For lists, items can also be appended using:
13# TAG += value [value, ...]
14# Values that contain spaces should be placed between quotes (\" \").
15
16#---------------------------------------------------------------------------
17# Project related configuration options
18#---------------------------------------------------------------------------
19
20# This tag specifies the encoding used for all characters in the config file
21# that follow. The default is UTF-8 which is also the encoding used for all text
22# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
23# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
24# for the list of possible encodings.
25# The default value is: UTF-8.
26
27DOXYFILE_ENCODING = UTF-8
28
29# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
30# double-quotes, unless you are using Doxywizard) that should identify the
31# project for which the documentation is generated. This name is used in the
32# title of most generated pages and in a few other places.
33# The default value is: My Project.
34
35PROJECT_NAME = Citra
36
37# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
38# could be handy for archiving the generated documentation or if some version
39# control system is used.
40
41PROJECT_NUMBER =
42
43# Using the PROJECT_BRIEF tag one can provide an optional one line description
44# for a project that appears at the top of each page and should give viewer a
45# quick idea about the purpose of the project. Keep the description short.
46
47PROJECT_BRIEF = "Nintendo 3DS emulator/debugger"
48
49# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
50# the documentation. The maximum height of the logo should not exceed 55 pixels
51# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
52# to the output directory.
53
54PROJECT_LOGO = doc-icon.png
55
56# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
57# into which the generated documentation will be written. If a relative path is
58# entered, it will be relative to the location where doxygen was started. If
59# left blank the current directory will be used.
60
61OUTPUT_DIRECTORY = doc-build/
62
63# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
64# directories (in 2 levels) under the output directory of each output format and
65# will distribute the generated files over these directories. Enabling this
66# option can be useful when feeding doxygen a huge amount of source files, where
67# putting all generated files in the same directory would otherwise causes
68# performance problems for the file system.
69# The default value is: NO.
70
71CREATE_SUBDIRS = NO
72
73# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
74# characters to appear in the names of generated files. If set to NO, non-ASCII
75# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
76# U+3044.
77# The default value is: NO.
78
79ALLOW_UNICODE_NAMES = NO
80
81# The OUTPUT_LANGUAGE tag is used to specify the language in which all
82# documentation generated by doxygen is written. Doxygen will use this
83# information to generate all constant output in the proper language.
84# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
85# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
86# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
87# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
88# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
89# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
90# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
91# Ukrainian and Vietnamese.
92# The default value is: English.
93
94OUTPUT_LANGUAGE = English
95
96# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
97# descriptions after the members that are listed in the file and class
98# documentation (similar to Javadoc). Set to NO to disable this.
99# The default value is: YES.
100
101BRIEF_MEMBER_DESC = YES
102
103# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
104# description of a member or function before the detailed description
105#
106# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
107# brief descriptions will be completely suppressed.
108# The default value is: YES.
109
110REPEAT_BRIEF = YES
111
112# This tag implements a quasi-intelligent brief description abbreviator that is
113# used to form the text in various listings. Each string in this list, if found
114# as the leading text of the brief description, will be stripped from the text
115# and the result, after processing the whole list, is used as the annotated
116# text. Otherwise, the brief description is used as-is. If left blank, the
117# following values are used ($name is automatically replaced with the name of
118# the entity):The $name class, The $name widget, The $name file, is, provides,
119# specifies, contains, represents, a, an and the.
120
121ABBREVIATE_BRIEF = "The $name class" \
122 "The $name widget" \
123 "The $name file" \
124 is \
125 provides \
126 specifies \
127 contains \
128 represents \
129 a \
130 an \
131 the
132
133# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
134# doxygen will generate a detailed section even if there is only a brief
135# description.
136# The default value is: NO.
137
138ALWAYS_DETAILED_SEC = NO
139
140# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
141# inherited members of a class in the documentation of that class as if those
142# members were ordinary class members. Constructors, destructors and assignment
143# operators of the base classes will not be shown.
144# The default value is: NO.
145
146INLINE_INHERITED_MEMB = NO
147
148# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
149# before files name in the file list and in the header files. If set to NO the
150# shortest path that makes the file name unique will be used
151# The default value is: YES.
152
153FULL_PATH_NAMES = YES
154
155# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
156# Stripping is only done if one of the specified strings matches the left-hand
157# part of the path. The tag can be used to show relative paths in the file list.
158# If left blank the directory from which doxygen is run is used as the path to
159# strip.
160#
161# Note that you can specify absolute paths here, but also relative paths, which
162# will be relative from the directory where doxygen is started.
163# This tag requires that the tag FULL_PATH_NAMES is set to YES.
164
165STRIP_FROM_PATH =
166
167# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
168# path mentioned in the documentation of a class, which tells the reader which
169# header file to include in order to use a class. If left blank only the name of
170# the header file containing the class definition is used. Otherwise one should
171# specify the list of include paths that are normally passed to the compiler
172# using the -I flag.
173
174STRIP_FROM_INC_PATH =
175
176# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
177# less readable) file names. This can be useful is your file systems doesn't
178# support long names like on DOS, Mac, or CD-ROM.
179# The default value is: NO.
180
181SHORT_NAMES = NO
182
183# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
184# first line (until the first dot) of a Javadoc-style comment as the brief
185# description. If set to NO, the Javadoc-style will behave just like regular Qt-
186# style comments (thus requiring an explicit @brief command for a brief
187# description.)
188# The default value is: NO.
189
190JAVADOC_AUTOBRIEF = YES
191
192# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
193# line (until the first dot) of a Qt-style comment as the brief description. If
194# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
195# requiring an explicit \brief command for a brief description.)
196# The default value is: NO.
197
198QT_AUTOBRIEF = NO
199
200# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
201# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
202# a brief description. This used to be the default behavior. The new default is
203# to treat a multi-line C++ comment block as a detailed description. Set this
204# tag to YES if you prefer the old behavior instead.
205#
206# Note that setting this tag to YES also means that rational rose comments are
207# not recognized any more.
208# The default value is: NO.
209
210MULTILINE_CPP_IS_BRIEF = YES
211
212# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
213# documentation from any documented member that it re-implements.
214# The default value is: YES.
215
216INHERIT_DOCS = YES
217
218# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
219# new page for each member. If set to NO, the documentation of a member will be
220# part of the file/class/namespace that contains it.
221# The default value is: NO.
222
223SEPARATE_MEMBER_PAGES = NO
224
225# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
226# uses this value to replace tabs by spaces in code fragments.
227# Minimum value: 1, maximum value: 16, default value: 4.
228
229TAB_SIZE = 4
230
231# This tag can be used to specify a number of aliases that act as commands in
232# the documentation. An alias has the form:
233# name=value
234# For example adding
235# "sideeffect=@par Side Effects:\n"
236# will allow you to put the command \sideeffect (or @sideeffect) in the
237# documentation, which will result in a user-defined paragraph with heading
238# "Side Effects:". You can put \n's in the value part of an alias to insert
239# newlines.
240
241ALIASES =
242
243# This tag can be used to specify a number of word-keyword mappings (TCL only).
244# A mapping has the form "name=value". For example adding "class=itcl::class"
245# will allow you to use the command class in the itcl::class meaning.
246
247TCL_SUBST =
248
249# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
250# only. Doxygen will then generate output that is more tailored for C. For
251# instance, some of the names that are used will be different. The list of all
252# members will be omitted, etc.
253# The default value is: NO.
254
255OPTIMIZE_OUTPUT_FOR_C = NO
256
257# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
258# Python sources only. Doxygen will then generate output that is more tailored
259# for that language. For instance, namespaces will be presented as packages,
260# qualified scopes will look different, etc.
261# The default value is: NO.
262
263OPTIMIZE_OUTPUT_JAVA = NO
264
265# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
266# sources. Doxygen will then generate output that is tailored for Fortran.
267# The default value is: NO.
268
269OPTIMIZE_FOR_FORTRAN = NO
270
271# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
272# sources. Doxygen will then generate output that is tailored for VHDL.
273# The default value is: NO.
274
275OPTIMIZE_OUTPUT_VHDL = NO
276
277# Doxygen selects the parser to use depending on the extension of the files it
278# parses. With this tag you can assign which parser to use for a given
279# extension. Doxygen has a built-in mapping, but you can override or extend it
280# using this tag. The format is ext=language, where ext is a file extension, and
281# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
282# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
283# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
284# Fortran. In the later case the parser tries to guess whether the code is fixed
285# or free formatted code, this is the default for Fortran type files), VHDL. For
286# instance to make doxygen treat .inc files as Fortran files (default is PHP),
287# and .f files as C (default is Fortran), use: inc=Fortran f=C.
288#
289# Note For files without extension you can use no_extension as a placeholder.
290#
291# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
292# the files are not read by doxygen.
293
294EXTENSION_MAPPING =
295
296# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
297# according to the Markdown format, which allows for more readable
298# documentation. See http://daringfireball.net/projects/markdown/ for details.
299# The output of markdown processing is further processed by doxygen, so you can
300# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
301# case of backward compatibilities issues.
302# The default value is: YES.
303
304MARKDOWN_SUPPORT = YES
305
306# When enabled doxygen tries to link words that correspond to documented
307# classes, or namespaces to their corresponding documentation. Such a link can
308# be prevented in individual cases by by putting a % sign in front of the word
309# or globally by setting AUTOLINK_SUPPORT to NO.
310# The default value is: YES.
311
312AUTOLINK_SUPPORT = YES
313
314# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
315# to include (a tag file for) the STL sources as input, then you should set this
316# tag to YES in order to let doxygen match functions declarations and
317# definitions whose arguments contain STL classes (e.g. func(std::string);
318# versus func(std::string) {}). This also make the inheritance and collaboration
319# diagrams that involve STL classes more complete and accurate.
320# The default value is: NO.
321
322BUILTIN_STL_SUPPORT = NO
323
324# If you use Microsoft's C++/CLI language, you should set this option to YES to
325# enable parsing support.
326# The default value is: NO.
327
328CPP_CLI_SUPPORT = NO
329
330# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
331# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
332# will parse them like normal C++ but will assume all classes use public instead
333# of private inheritance when no explicit protection keyword is present.
334# The default value is: NO.
335
336SIP_SUPPORT = NO
337
338# For Microsoft's IDL there are propget and propput attributes to indicate
339# getter and setter methods for a property. Setting this option to YES will make
340# doxygen to replace the get and set methods by a property in the documentation.
341# This will only work if the methods are indeed getting or setting a simple
342# type. If this is not the case, or you want to show the methods anyway, you
343# should set this option to NO.
344# The default value is: YES.
345
346IDL_PROPERTY_SUPPORT = NO
347
348# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
349# tag is set to YES, then doxygen will reuse the documentation of the first
350# member in the group (if any) for the other members of the group. By default
351# all members of a group must be documented explicitly.
352# The default value is: NO.
353
354DISTRIBUTE_GROUP_DOC = NO
355
356# Set the SUBGROUPING tag to YES to allow class member groups of the same type
357# (for instance a group of public functions) to be put as a subgroup of that
358# type (e.g. under the Public Functions section). Set it to NO to prevent
359# subgrouping. Alternatively, this can be done per class using the
360# \nosubgrouping command.
361# The default value is: YES.
362
363SUBGROUPING = YES
364
365# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
366# are shown inside the group in which they are included (e.g. using \ingroup)
367# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
368# and RTF).
369#
370# Note that this feature does not work in combination with
371# SEPARATE_MEMBER_PAGES.
372# The default value is: NO.
373
374INLINE_GROUPED_CLASSES = NO
375
376# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
377# with only public data fields or simple typedef fields will be shown inline in
378# the documentation of the scope in which they are defined (i.e. file,
379# namespace, or group documentation), provided this scope is documented. If set
380# to NO, structs, classes, and unions are shown on a separate page (for HTML and
381# Man pages) or section (for LaTeX and RTF).
382# The default value is: NO.
383
384INLINE_SIMPLE_STRUCTS = YES
385
386# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
387# enum is documented as struct, union, or enum with the name of the typedef. So
388# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
389# with name TypeT. When disabled the typedef will appear as a member of a file,
390# namespace, or class. And the struct will be named TypeS. This can typically be
391# useful for C code in case the coding convention dictates that all compound
392# types are typedef'ed and only the typedef is referenced, never the tag name.
393# The default value is: NO.
394
395TYPEDEF_HIDES_STRUCT = NO
396
397# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
398# cache is used to resolve symbols given their name and scope. Since this can be
399# an expensive process and often the same symbol appears multiple times in the
400# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
401# doxygen will become slower. If the cache is too large, memory is wasted. The
402# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
403# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
404# symbols. At the end of a run doxygen will report the cache usage and suggest
405# the optimal cache size from a speed point of view.
406# Minimum value: 0, maximum value: 9, default value: 0.
407
408LOOKUP_CACHE_SIZE = 0
409
410#---------------------------------------------------------------------------
411# Build related configuration options
412#---------------------------------------------------------------------------
413
414# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
415# documentation are documented, even if no documentation was available. Private
416# class members and static file members will be hidden unless the
417# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
418# Note: This will also disable the warnings about undocumented members that are
419# normally produced when WARNINGS is set to YES.
420# The default value is: NO.
421
422EXTRACT_ALL = NO
423
424# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
425# be included in the documentation.
426# The default value is: NO.
427
428EXTRACT_PRIVATE = YES
429
430# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
431# scope will be included in the documentation.
432# The default value is: NO.
433
434EXTRACT_PACKAGE = NO
435
436# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
437# included in the documentation.
438# The default value is: NO.
439
440EXTRACT_STATIC = YES
441
442# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
443# locally in source files will be included in the documentation. If set to NO
444# only classes defined in header files are included. Does not have any effect
445# for Java sources.
446# The default value is: YES.
447
448EXTRACT_LOCAL_CLASSES = YES
449
450# This flag is only useful for Objective-C code. When set to YES local methods,
451# which are defined in the implementation section but not in the interface are
452# included in the documentation. If set to NO only methods in the interface are
453# included.
454# The default value is: NO.
455
456EXTRACT_LOCAL_METHODS = NO
457
458# If this flag is set to YES, the members of anonymous namespaces will be
459# extracted and appear in the documentation as a namespace called
460# 'anonymous_namespace{file}', where file will be replaced with the base name of
461# the file that contains the anonymous namespace. By default anonymous namespace
462# are hidden.
463# The default value is: NO.
464
465EXTRACT_ANON_NSPACES = NO
466
467# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
468# undocumented members inside documented classes or files. If set to NO these
469# members will be included in the various overviews, but no documentation
470# section is generated. This option has no effect if EXTRACT_ALL is enabled.
471# The default value is: NO.
472
473HIDE_UNDOC_MEMBERS = NO
474
475# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
476# undocumented classes that are normally visible in the class hierarchy. If set
477# to NO these classes will be included in the various overviews. This option has
478# no effect if EXTRACT_ALL is enabled.
479# The default value is: NO.
480
481HIDE_UNDOC_CLASSES = NO
482
483# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
484# (class|struct|union) declarations. If set to NO these declarations will be
485# included in the documentation.
486# The default value is: NO.
487
488HIDE_FRIEND_COMPOUNDS = NO
489
490# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
491# documentation blocks found inside the body of a function. If set to NO these
492# blocks will be appended to the function's detailed documentation block.
493# The default value is: NO.
494
495HIDE_IN_BODY_DOCS = NO
496
497# The INTERNAL_DOCS tag determines if documentation that is typed after a
498# \internal command is included. If the tag is set to NO then the documentation
499# will be excluded. Set it to YES to include the internal documentation.
500# The default value is: NO.
501
502INTERNAL_DOCS = NO
503
504# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
505# names in lower-case letters. If set to YES upper-case letters are also
506# allowed. This is useful if you have classes or files whose names only differ
507# in case and if your file system supports case sensitive file names. Windows
508# and Mac users are advised to set this option to NO.
509# The default value is: system dependent.
510
511CASE_SENSE_NAMES = NO
512
513# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
514# their full class and namespace scopes in the documentation. If set to YES the
515# scope will be hidden.
516# The default value is: NO.
517
518HIDE_SCOPE_NAMES = NO
519
520# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
521# the files that are included by a file in the documentation of that file.
522# The default value is: YES.
523
524SHOW_INCLUDE_FILES = YES
525
526# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
527# grouped member an include statement to the documentation, telling the reader
528# which file to include in order to use the member.
529# The default value is: NO.
530
531SHOW_GROUPED_MEMB_INC = NO
532
533# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
534# files with double quotes in the documentation rather than with sharp brackets.
535# The default value is: NO.
536
537FORCE_LOCAL_INCLUDES = NO
538
539# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
540# documentation for inline members.
541# The default value is: YES.
542
543INLINE_INFO = YES
544
545# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
546# (detailed) documentation of file and class members alphabetically by member
547# name. If set to NO the members will appear in declaration order.
548# The default value is: YES.
549
550SORT_MEMBER_DOCS = YES
551
552# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
553# descriptions of file, namespace and class members alphabetically by member
554# name. If set to NO the members will appear in declaration order. Note that
555# this will also influence the order of the classes in the class list.
556# The default value is: NO.
557
558SORT_BRIEF_DOCS = NO
559
560# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
561# (brief and detailed) documentation of class members so that constructors and
562# destructors are listed first. If set to NO the constructors will appear in the
563# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
564# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
565# member documentation.
566# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
567# detailed member documentation.
568# The default value is: NO.
569
570SORT_MEMBERS_CTORS_1ST = NO
571
572# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
573# of group names into alphabetical order. If set to NO the group names will
574# appear in their defined order.
575# The default value is: NO.
576
577SORT_GROUP_NAMES = NO
578
579# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
580# fully-qualified names, including namespaces. If set to NO, the class list will
581# be sorted only by class name, not including the namespace part.
582# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
583# Note: This option applies only to the class list, not to the alphabetical
584# list.
585# The default value is: NO.
586
587SORT_BY_SCOPE_NAME = NO
588
589# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
590# type resolution of all parameters of a function it will reject a match between
591# the prototype and the implementation of a member function even if there is
592# only one candidate or it is obvious which candidate to choose by doing a
593# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
594# accept a match between prototype and implementation in such cases.
595# The default value is: NO.
596
597STRICT_PROTO_MATCHING = NO
598
599# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
600# todo list. This list is created by putting \todo commands in the
601# documentation.
602# The default value is: YES.
603
604GENERATE_TODOLIST = YES
605
606# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
607# test list. This list is created by putting \test commands in the
608# documentation.
609# The default value is: YES.
610
611GENERATE_TESTLIST = YES
612
613# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
614# list. This list is created by putting \bug commands in the documentation.
615# The default value is: YES.
616
617GENERATE_BUGLIST = YES
618
619# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
620# the deprecated list. This list is created by putting \deprecated commands in
621# the documentation.
622# The default value is: YES.
623
624GENERATE_DEPRECATEDLIST= YES
625
626# The ENABLED_SECTIONS tag can be used to enable conditional documentation
627# sections, marked by \if <section_label> ... \endif and \cond <section_label>
628# ... \endcond blocks.
629
630ENABLED_SECTIONS =
631
632# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
633# initial value of a variable or macro / define can have for it to appear in the
634# documentation. If the initializer consists of more lines than specified here
635# it will be hidden. Use a value of 0 to hide initializers completely. The
636# appearance of the value of individual variables and macros / defines can be
637# controlled using \showinitializer or \hideinitializer command in the
638# documentation regardless of this setting.
639# Minimum value: 0, maximum value: 10000, default value: 30.
640
641MAX_INITIALIZER_LINES = 30
642
643# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
644# the bottom of the documentation of classes and structs. If set to YES the list
645# will mention the files that were used to generate the documentation.
646# The default value is: YES.
647
648SHOW_USED_FILES = YES
649
650# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
651# will remove the Files entry from the Quick Index and from the Folder Tree View
652# (if specified).
653# The default value is: YES.
654
655SHOW_FILES = YES
656
657# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
658# page. This will remove the Namespaces entry from the Quick Index and from the
659# Folder Tree View (if specified).
660# The default value is: YES.
661
662SHOW_NAMESPACES = YES
663
664# The FILE_VERSION_FILTER tag can be used to specify a program or script that
665# doxygen should invoke to get the current version for each file (typically from
666# the version control system). Doxygen will invoke the program by executing (via
667# popen()) the command command input-file, where command is the value of the
668# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
669# by doxygen. Whatever the program writes to standard output is used as the file
670# version. For an example see the documentation.
671
672FILE_VERSION_FILTER =
673
674# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
675# by doxygen. The layout file controls the global structure of the generated
676# output files in an output format independent way. To create the layout file
677# that represents doxygen's defaults, run doxygen with the -l option. You can
678# optionally specify a file name after the option, if omitted DoxygenLayout.xml
679# will be used as the name of the layout file.
680#
681# Note that if you run doxygen from a directory containing a file called
682# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
683# tag is left empty.
684
685LAYOUT_FILE =
686
687# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
688# the reference definitions. This must be a list of .bib files. The .bib
689# extension is automatically appended if omitted. This requires the bibtex tool
690# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
691# For LaTeX the style of the bibliography can be controlled using
692# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
693# search path. See also \cite for info how to create references.
694
695CITE_BIB_FILES =
696
697#---------------------------------------------------------------------------
698# Configuration options related to warning and progress messages
699#---------------------------------------------------------------------------
700
701# The QUIET tag can be used to turn on/off the messages that are generated to
702# standard output by doxygen. If QUIET is set to YES this implies that the
703# messages are off.
704# The default value is: NO.
705
706QUIET = YES
707
708# The WARNINGS tag can be used to turn on/off the warning messages that are
709# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
710# this implies that the warnings are on.
711#
712# Tip: Turn warnings on while writing the documentation.
713# The default value is: YES.
714
715WARNINGS = YES
716
717# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
718# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
719# will automatically be disabled.
720# The default value is: YES.
721
722WARN_IF_UNDOCUMENTED = NO
723
724# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
725# potential errors in the documentation, such as not documenting some parameters
726# in a documented function, or documenting parameters that don't exist or using
727# markup commands wrongly.
728# The default value is: YES.
729
730WARN_IF_DOC_ERROR = YES
731
732# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
733# are documented, but have no documentation for their parameters or return
734# value. If set to NO doxygen will only warn about wrong or incomplete parameter
735# documentation, but not about the absence of documentation.
736# The default value is: NO.
737
738WARN_NO_PARAMDOC = NO
739
740# The WARN_FORMAT tag determines the format of the warning messages that doxygen
741# can produce. The string should contain the $file, $line, and $text tags, which
742# will be replaced by the file and line number from which the warning originated
743# and the warning text. Optionally the format may contain $version, which will
744# be replaced by the version of the file (if it could be obtained via
745# FILE_VERSION_FILTER)
746# The default value is: $file:$line: $text.
747
748WARN_FORMAT = "$file:$line: $text"
749
750# The WARN_LOGFILE tag can be used to specify a file to which warning and error
751# messages should be written. If left blank the output is written to standard
752# error (stderr).
753
754WARN_LOGFILE =
755
756#---------------------------------------------------------------------------
757# Configuration options related to the input files
758#---------------------------------------------------------------------------
759
760# The INPUT tag is used to specify the files and/or directories that contain
761# documented source files. You may enter file names like myfile.cpp or
762# directories like /usr/src/myproject. Separate the files or directories with
763# spaces.
764# Note: If this tag is empty the current directory is searched.
765
766INPUT = src/
767
768# This tag can be used to specify the character encoding of the source files
769# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
770# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
771# documentation (see: http://www.gnu.org/software/libiconv) for the list of
772# possible encodings.
773# The default value is: UTF-8.
774
775INPUT_ENCODING = UTF-8
776
777# If the value of the INPUT tag contains directories, you can use the
778# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
779# *.h) to filter out the source-files in the directories. If left blank the
780# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
781# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
782# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
783# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
784# *.qsf, *.as and *.js.
785
786FILE_PATTERNS = *.c \
787 *.cc \
788 *.cxx \
789 *.cpp \
790 *.c++ \
791 *.h \
792 *.hh \
793 *.hxx \
794 *.hpp \
795 *.h++
796
797# The RECURSIVE tag can be used to specify whether or not subdirectories should
798# be searched for input files as well.
799# The default value is: NO.
800
801RECURSIVE = YES
802
803# The EXCLUDE tag can be used to specify files and/or directories that should be
804# excluded from the INPUT source files. This way you can easily exclude a
805# subdirectory from a directory tree whose root is specified with the INPUT tag.
806#
807# Note that relative paths are relative to the directory from which doxygen is
808# run.
809
810EXCLUDE =
811
812# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
813# directories that are symbolic links (a Unix file system feature) are excluded
814# from the input.
815# The default value is: NO.
816
817EXCLUDE_SYMLINKS = NO
818
819# If the value of the INPUT tag contains directories, you can use the
820# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
821# certain files from those directories.
822#
823# Note that the wildcards are matched against the file with absolute path, so to
824# exclude all test directories for example use the pattern */test/*
825
826EXCLUDE_PATTERNS =
827
828# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
829# (namespaces, classes, functions, etc.) that should be excluded from the
830# output. The symbol name can be a fully qualified name, a word, or if the
831# wildcard * is used, a substring. Examples: ANamespace, AClass,
832# AClass::ANamespace, ANamespace::*Test
833#
834# Note that the wildcards are matched against the file with absolute path, so to
835# exclude all test directories use the pattern */test/*
836
837EXCLUDE_SYMBOLS =
838
839# The EXAMPLE_PATH tag can be used to specify one or more files or directories
840# that contain example code fragments that are included (see the \include
841# command).
842
843EXAMPLE_PATH =
844
845# If the value of the EXAMPLE_PATH tag contains directories, you can use the
846# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
847# *.h) to filter out the source-files in the directories. If left blank all
848# files are included.
849
850EXAMPLE_PATTERNS = *
851
852# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
853# searched for input files to be used with the \include or \dontinclude commands
854# irrespective of the value of the RECURSIVE tag.
855# The default value is: NO.
856
857EXAMPLE_RECURSIVE = NO
858
859# The IMAGE_PATH tag can be used to specify one or more files or directories
860# that contain images that are to be included in the documentation (see the
861# \image command).
862
863IMAGE_PATH =
864
865# The INPUT_FILTER tag can be used to specify a program that doxygen should
866# invoke to filter for each input file. Doxygen will invoke the filter program
867# by executing (via popen()) the command:
868#
869# <filter> <input-file>
870#
871# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
872# name of an input file. Doxygen will then use the output that the filter
873# program writes to standard output. If FILTER_PATTERNS is specified, this tag
874# will be ignored.
875#
876# Note that the filter must not add or remove lines; it is applied before the
877# code is scanned, but not when the output code is generated. If lines are added
878# or removed, the anchors will not be placed correctly.
879
880INPUT_FILTER =
881
882# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
883# basis. Doxygen will compare the file name with each pattern and apply the
884# filter if there is a match. The filters are a list of the form: pattern=filter
885# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
886# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
887# patterns match the file name, INPUT_FILTER is applied.
888
889FILTER_PATTERNS =
890
891# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
892# INPUT_FILTER ) will also be used to filter the input files that are used for
893# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
894# The default value is: NO.
895
896FILTER_SOURCE_FILES = NO
897
898# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
899# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
900# it is also possible to disable source filtering for a specific pattern using
901# *.ext= (so without naming a filter).
902# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
903
904FILTER_SOURCE_PATTERNS =
905
906# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
907# is part of the input, its contents will be placed on the main page
908# (index.html). This can be useful if you have a project on for instance GitHub
909# and want to reuse the introduction page also for the doxygen output.
910
911USE_MDFILE_AS_MAINPAGE =
912
913#---------------------------------------------------------------------------
914# Configuration options related to source browsing
915#---------------------------------------------------------------------------
916
917# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
918# generated. Documented entities will be cross-referenced with these sources.
919#
920# Note: To get rid of all source code in the generated output, make sure that
921# also VERBATIM_HEADERS is set to NO.
922# The default value is: NO.
923
924SOURCE_BROWSER = YES
925
926# Setting the INLINE_SOURCES tag to YES will include the body of functions,
927# classes and enums directly into the documentation.
928# The default value is: NO.
929
930INLINE_SOURCES = NO
931
932# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
933# special comment blocks from generated source code fragments. Normal C, C++ and
934# Fortran comments will always remain visible.
935# The default value is: YES.
936
937STRIP_CODE_COMMENTS = YES
938
939# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
940# function all documented functions referencing it will be listed.
941# The default value is: NO.
942
943REFERENCED_BY_RELATION = NO
944
945# If the REFERENCES_RELATION tag is set to YES then for each documented function
946# all documented entities called/used by that function will be listed.
947# The default value is: NO.
948
949REFERENCES_RELATION = NO
950
951# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
952# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
953# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
954# link to the documentation.
955# The default value is: YES.
956
957REFERENCES_LINK_SOURCE = YES
958
959# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
960# source code will show a tooltip with additional information such as prototype,
961# brief description and links to the definition and documentation. Since this
962# will make the HTML file larger and loading of large files a bit slower, you
963# can opt to disable this feature.
964# The default value is: YES.
965# This tag requires that the tag SOURCE_BROWSER is set to YES.
966
967SOURCE_TOOLTIPS = YES
968
969# If the USE_HTAGS tag is set to YES then the references to source code will
970# point to the HTML generated by the htags(1) tool instead of doxygen built-in
971# source browser. The htags tool is part of GNU's global source tagging system
972# (see http://www.gnu.org/software/global/global.html). You will need version
973# 4.8.6 or higher.
974#
975# To use it do the following:
976# - Install the latest version of global
977# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
978# - Make sure the INPUT points to the root of the source tree
979# - Run doxygen as normal
980#
981# Doxygen will invoke htags (and that will in turn invoke gtags), so these
982# tools must be available from the command line (i.e. in the search path).
983#
984# The result: instead of the source browser generated by doxygen, the links to
985# source code will now point to the output of htags.
986# The default value is: NO.
987# This tag requires that the tag SOURCE_BROWSER is set to YES.
988
989USE_HTAGS = NO
990
991# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
992# verbatim copy of the header file for each class for which an include is
993# specified. Set to NO to disable this.
994# See also: Section \class.
995# The default value is: YES.
996
997VERBATIM_HEADERS = YES
998
999# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
1000# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
1001# cost of reduced performance. This can be particularly helpful with template
1002# rich C++ code for which doxygen's built-in parser lacks the necessary type
1003# information.
1004# Note: The availability of this option depends on whether or not doxygen was
1005# compiled with the --with-libclang option.
1006# The default value is: NO.
1007
1008CLANG_ASSISTED_PARSING = NO
1009
1010# If clang assisted parsing is enabled you can provide the compiler with command
1011# line options that you would normally use when invoking the compiler. Note that
1012# the include paths will already be set by doxygen for the files and directories
1013# specified with INPUT and INCLUDE_PATH.
1014# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
1015
1016CLANG_OPTIONS =
1017
1018#---------------------------------------------------------------------------
1019# Configuration options related to the alphabetical class index
1020#---------------------------------------------------------------------------
1021
1022# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
1023# compounds will be generated. Enable this if the project contains a lot of
1024# classes, structs, unions or interfaces.
1025# The default value is: YES.
1026
1027ALPHABETICAL_INDEX = YES
1028
1029# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
1030# which the alphabetical index list will be split.
1031# Minimum value: 1, maximum value: 20, default value: 5.
1032# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
1033
1034COLS_IN_ALPHA_INDEX = 5
1035
1036# In case all classes in a project start with a common prefix, all classes will
1037# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
1038# can be used to specify a prefix (or a list of prefixes) that should be ignored
1039# while generating the index headers.
1040# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
1041
1042IGNORE_PREFIX =
1043
1044#---------------------------------------------------------------------------
1045# Configuration options related to the HTML output
1046#---------------------------------------------------------------------------
1047
1048# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
1049# The default value is: YES.
1050
1051GENERATE_HTML = YES
1052
1053# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
1054# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
1055# it.
1056# The default directory is: html.
1057# This tag requires that the tag GENERATE_HTML is set to YES.
1058
1059HTML_OUTPUT = html
1060
1061# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
1062# generated HTML page (for example: .htm, .php, .asp).
1063# The default value is: .html.
1064# This tag requires that the tag GENERATE_HTML is set to YES.
1065
1066HTML_FILE_EXTENSION = .html
1067
1068# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
1069# each generated HTML page. If the tag is left blank doxygen will generate a
1070# standard header.
1071#
1072# To get valid HTML the header file that includes any scripts and style sheets
1073# that doxygen needs, which is dependent on the configuration options used (e.g.
1074# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
1075# default header using
1076# doxygen -w html new_header.html new_footer.html new_stylesheet.css
1077# YourConfigFile
1078# and then modify the file new_header.html. See also section "Doxygen usage"
1079# for information on how to generate the default header that doxygen normally
1080# uses.
1081# Note: The header is subject to change so you typically have to regenerate the
1082# default header when upgrading to a newer version of doxygen. For a description
1083# of the possible markers and block names see the documentation.
1084# This tag requires that the tag GENERATE_HTML is set to YES.
1085
1086HTML_HEADER =
1087
1088# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
1089# generated HTML page. If the tag is left blank doxygen will generate a standard
1090# footer. See HTML_HEADER for more information on how to generate a default
1091# footer and what special commands can be used inside the footer. See also
1092# section "Doxygen usage" for information on how to generate the default footer
1093# that doxygen normally uses.
1094# This tag requires that the tag GENERATE_HTML is set to YES.
1095
1096HTML_FOOTER =
1097
1098# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
1099# sheet that is used by each HTML page. It can be used to fine-tune the look of
1100# the HTML output. If left blank doxygen will generate a default style sheet.
1101# See also section "Doxygen usage" for information on how to generate the style
1102# sheet that doxygen normally uses.
1103# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
1104# it is more robust and this tag (HTML_STYLESHEET) will in the future become
1105# obsolete.
1106# This tag requires that the tag GENERATE_HTML is set to YES.
1107
1108HTML_STYLESHEET =
1109
1110# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
1111# cascading style sheets that are included after the standard style sheets
1112# created by doxygen. Using this option one can overrule certain style aspects.
1113# This is preferred over using HTML_STYLESHEET since it does not replace the
1114# standard style sheet and is therefor more robust against future updates.
1115# Doxygen will copy the style sheet files to the output directory.
1116# Note: The order of the extra stylesheet files is of importance (e.g. the last
1117# stylesheet in the list overrules the setting of the previous ones in the
1118# list). For an example see the documentation.
1119# This tag requires that the tag GENERATE_HTML is set to YES.
1120
1121HTML_EXTRA_STYLESHEET =
1122
1123# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
1124# other source files which should be copied to the HTML output directory. Note
1125# that these files will be copied to the base HTML output directory. Use the
1126# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
1127# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
1128# files will be copied as-is; there are no commands or markers available.
1129# This tag requires that the tag GENERATE_HTML is set to YES.
1130
1131HTML_EXTRA_FILES =
1132
1133# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
1134# will adjust the colors in the stylesheet and background images according to
1135# this color. Hue is specified as an angle on a colorwheel, see
1136# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
1137# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
1138# purple, and 360 is red again.
1139# Minimum value: 0, maximum value: 359, default value: 220.
1140# This tag requires that the tag GENERATE_HTML is set to YES.
1141
1142HTML_COLORSTYLE_HUE = 220
1143
1144# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
1145# in the HTML output. For a value of 0 the output will use grayscales only. A
1146# value of 255 will produce the most vivid colors.
1147# Minimum value: 0, maximum value: 255, default value: 100.
1148# This tag requires that the tag GENERATE_HTML is set to YES.
1149
1150HTML_COLORSTYLE_SAT = 100
1151
1152# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
1153# luminance component of the colors in the HTML output. Values below 100
1154# gradually make the output lighter, whereas values above 100 make the output
1155# darker. The value divided by 100 is the actual gamma applied, so 80 represents
1156# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
1157# change the gamma.
1158# Minimum value: 40, maximum value: 240, default value: 80.
1159# This tag requires that the tag GENERATE_HTML is set to YES.
1160
1161HTML_COLORSTYLE_GAMMA = 80
1162
1163# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
1164# page will contain the date and time when the page was generated. Setting this
1165# to NO can help when comparing the output of multiple runs.
1166# The default value is: YES.
1167# This tag requires that the tag GENERATE_HTML is set to YES.
1168
1169HTML_TIMESTAMP = YES
1170
1171# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
1172# documentation will contain sections that can be hidden and shown after the
1173# page has loaded.
1174# The default value is: NO.
1175# This tag requires that the tag GENERATE_HTML is set to YES.
1176
1177HTML_DYNAMIC_SECTIONS = NO
1178
1179# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
1180# shown in the various tree structured indices initially; the user can expand
1181# and collapse entries dynamically later on. Doxygen will expand the tree to
1182# such a level that at most the specified number of entries are visible (unless
1183# a fully collapsed tree already exceeds this amount). So setting the number of
1184# entries 1 will produce a full collapsed tree by default. 0 is a special value
1185# representing an infinite number of entries and will result in a full expanded
1186# tree by default.
1187# Minimum value: 0, maximum value: 9999, default value: 100.
1188# This tag requires that the tag GENERATE_HTML is set to YES.
1189
1190HTML_INDEX_NUM_ENTRIES = 100
1191
1192# If the GENERATE_DOCSET tag is set to YES, additional index files will be
1193# generated that can be used as input for Apple's Xcode 3 integrated development
1194# environment (see: http://developer.apple.com/tools/xcode/), introduced with
1195# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
1196# Makefile in the HTML output directory. Running make will produce the docset in
1197# that directory and running make install will install the docset in
1198# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
1199# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
1200# for more information.
1201# The default value is: NO.
1202# This tag requires that the tag GENERATE_HTML is set to YES.
1203
1204GENERATE_DOCSET = NO
1205
1206# This tag determines the name of the docset feed. A documentation feed provides
1207# an umbrella under which multiple documentation sets from a single provider
1208# (such as a company or product suite) can be grouped.
1209# The default value is: Doxygen generated docs.
1210# This tag requires that the tag GENERATE_DOCSET is set to YES.
1211
1212DOCSET_FEEDNAME = "Doxygen generated docs"
1213
1214# This tag specifies a string that should uniquely identify the documentation
1215# set bundle. This should be a reverse domain-name style string, e.g.
1216# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
1217# The default value is: org.doxygen.Project.
1218# This tag requires that the tag GENERATE_DOCSET is set to YES.
1219
1220DOCSET_BUNDLE_ID = org.doxygen.Project
1221
1222# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
1223# the documentation publisher. This should be a reverse domain-name style
1224# string, e.g. com.mycompany.MyDocSet.documentation.
1225# The default value is: org.doxygen.Publisher.
1226# This tag requires that the tag GENERATE_DOCSET is set to YES.
1227
1228DOCSET_PUBLISHER_ID = org.doxygen.Publisher
1229
1230# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
1231# The default value is: Publisher.
1232# This tag requires that the tag GENERATE_DOCSET is set to YES.
1233
1234DOCSET_PUBLISHER_NAME = Publisher
1235
1236# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
1237# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
1238# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
1239# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
1240# Windows.
1241#
1242# The HTML Help Workshop contains a compiler that can convert all HTML output
1243# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
1244# files are now used as the Windows 98 help format, and will replace the old
1245# Windows help format (.hlp) on all Windows platforms in the future. Compressed
1246# HTML files also contain an index, a table of contents, and you can search for
1247# words in the documentation. The HTML workshop also contains a viewer for
1248# compressed HTML files.
1249# The default value is: NO.
1250# This tag requires that the tag GENERATE_HTML is set to YES.
1251
1252GENERATE_HTMLHELP = NO
1253
1254# The CHM_FILE tag can be used to specify the file name of the resulting .chm
1255# file. You can add a path in front of the file if the result should not be
1256# written to the html output directory.
1257# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1258
1259CHM_FILE =
1260
1261# The HHC_LOCATION tag can be used to specify the location (absolute path
1262# including file name) of the HTML help compiler ( hhc.exe). If non-empty
1263# doxygen will try to run the HTML help compiler on the generated index.hhp.
1264# The file has to be specified with full path.
1265# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1266
1267HHC_LOCATION =
1268
1269# The GENERATE_CHI flag controls if a separate .chi index file is generated (
1270# YES) or that it should be included in the master .chm file ( NO).
1271# The default value is: NO.
1272# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1273
1274GENERATE_CHI = NO
1275
1276# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
1277# and project file content.
1278# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1279
1280CHM_INDEX_ENCODING =
1281
1282# The BINARY_TOC flag controls whether a binary table of contents is generated (
1283# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
1284# enables the Previous and Next buttons.
1285# The default value is: NO.
1286# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1287
1288BINARY_TOC = NO
1289
1290# The TOC_EXPAND flag can be set to YES to add extra items for group members to
1291# the table of contents of the HTML help documentation and to the tree view.
1292# The default value is: NO.
1293# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1294
1295TOC_EXPAND = NO
1296
1297# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
1298# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
1299# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
1300# (.qch) of the generated HTML documentation.
1301# The default value is: NO.
1302# This tag requires that the tag GENERATE_HTML is set to YES.
1303
1304GENERATE_QHP = NO
1305
1306# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
1307# the file name of the resulting .qch file. The path specified is relative to
1308# the HTML output folder.
1309# This tag requires that the tag GENERATE_QHP is set to YES.
1310
1311QCH_FILE =
1312
1313# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
1314# Project output. For more information please see Qt Help Project / Namespace
1315# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
1316# The default value is: org.doxygen.Project.
1317# This tag requires that the tag GENERATE_QHP is set to YES.
1318
1319QHP_NAMESPACE = org.doxygen.Project
1320
1321# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
1322# Help Project output. For more information please see Qt Help Project / Virtual
1323# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
1324# folders).
1325# The default value is: doc.
1326# This tag requires that the tag GENERATE_QHP is set to YES.
1327
1328QHP_VIRTUAL_FOLDER = doc
1329
1330# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
1331# filter to add. For more information please see Qt Help Project / Custom
1332# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
1333# filters).
1334# This tag requires that the tag GENERATE_QHP is set to YES.
1335
1336QHP_CUST_FILTER_NAME =
1337
1338# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
1339# custom filter to add. For more information please see Qt Help Project / Custom
1340# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
1341# filters).
1342# This tag requires that the tag GENERATE_QHP is set to YES.
1343
1344QHP_CUST_FILTER_ATTRS =
1345
1346# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
1347# project's filter section matches. Qt Help Project / Filter Attributes (see:
1348# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
1349# This tag requires that the tag GENERATE_QHP is set to YES.
1350
1351QHP_SECT_FILTER_ATTRS =
1352
1353# The QHG_LOCATION tag can be used to specify the location of Qt's
1354# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
1355# generated .qhp file.
1356# This tag requires that the tag GENERATE_QHP is set to YES.
1357
1358QHG_LOCATION =
1359
1360# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
1361# generated, together with the HTML files, they form an Eclipse help plugin. To
1362# install this plugin and make it available under the help contents menu in
1363# Eclipse, the contents of the directory containing the HTML and XML files needs
1364# to be copied into the plugins directory of eclipse. The name of the directory
1365# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
1366# After copying Eclipse needs to be restarted before the help appears.
1367# The default value is: NO.
1368# This tag requires that the tag GENERATE_HTML is set to YES.
1369
1370GENERATE_ECLIPSEHELP = NO
1371
1372# A unique identifier for the Eclipse help plugin. When installing the plugin
1373# the directory name containing the HTML and XML files should also have this
1374# name. Each documentation set should have its own identifier.
1375# The default value is: org.doxygen.Project.
1376# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
1377
1378ECLIPSE_DOC_ID = org.doxygen.Project
1379
1380# If you want full control over the layout of the generated HTML pages it might
1381# be necessary to disable the index and replace it with your own. The
1382# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
1383# of each HTML page. A value of NO enables the index and the value YES disables
1384# it. Since the tabs in the index contain the same information as the navigation
1385# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
1386# The default value is: NO.
1387# This tag requires that the tag GENERATE_HTML is set to YES.
1388
1389DISABLE_INDEX = NO
1390
1391# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
1392# structure should be generated to display hierarchical information. If the tag
1393# value is set to YES, a side panel will be generated containing a tree-like
1394# index structure (just like the one that is generated for HTML Help). For this
1395# to work a browser that supports JavaScript, DHTML, CSS and frames is required
1396# (i.e. any modern browser). Windows users are probably better off using the
1397# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
1398# further fine-tune the look of the index. As an example, the default style
1399# sheet generated by doxygen has an example that shows how to put an image at
1400# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
1401# the same information as the tab index, you could consider setting
1402# DISABLE_INDEX to YES when enabling this option.
1403# The default value is: NO.
1404# This tag requires that the tag GENERATE_HTML is set to YES.
1405
1406GENERATE_TREEVIEW = YES
1407
1408# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
1409# doxygen will group on one line in the generated HTML documentation.
1410#
1411# Note that a value of 0 will completely suppress the enum values from appearing
1412# in the overview section.
1413# Minimum value: 0, maximum value: 20, default value: 4.
1414# This tag requires that the tag GENERATE_HTML is set to YES.
1415
1416ENUM_VALUES_PER_LINE = 4
1417
1418# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
1419# to set the initial width (in pixels) of the frame in which the tree is shown.
1420# Minimum value: 0, maximum value: 1500, default value: 250.
1421# This tag requires that the tag GENERATE_HTML is set to YES.
1422
1423TREEVIEW_WIDTH = 250
1424
1425# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
1426# external symbols imported via tag files in a separate window.
1427# The default value is: NO.
1428# This tag requires that the tag GENERATE_HTML is set to YES.
1429
1430EXT_LINKS_IN_WINDOW = NO
1431
1432# Use this tag to change the font size of LaTeX formulas included as images in
1433# the HTML documentation. When you change the font size after a successful
1434# doxygen run you need to manually remove any form_*.png images from the HTML
1435# output directory to force them to be regenerated.
1436# Minimum value: 8, maximum value: 50, default value: 10.
1437# This tag requires that the tag GENERATE_HTML is set to YES.
1438
1439FORMULA_FONTSIZE = 10
1440
1441# Use the FORMULA_TRANPARENT tag to determine whether or not the images
1442# generated for formulas are transparent PNGs. Transparent PNGs are not
1443# supported properly for IE 6.0, but are supported on all modern browsers.
1444#
1445# Note that when changing this option you need to delete any form_*.png files in
1446# the HTML output directory before the changes have effect.
1447# The default value is: YES.
1448# This tag requires that the tag GENERATE_HTML is set to YES.
1449
1450FORMULA_TRANSPARENT = YES
1451
1452# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
1453# http://www.mathjax.org) which uses client side Javascript for the rendering
1454# instead of using prerendered bitmaps. Use this if you do not have LaTeX
1455# installed or if you want to formulas look prettier in the HTML output. When
1456# enabled you may also need to install MathJax separately and configure the path
1457# to it using the MATHJAX_RELPATH option.
1458# The default value is: NO.
1459# This tag requires that the tag GENERATE_HTML is set to YES.
1460
1461USE_MATHJAX = NO
1462
1463# When MathJax is enabled you can set the default output format to be used for
1464# the MathJax output. See the MathJax site (see:
1465# http://docs.mathjax.org/en/latest/output.html) for more details.
1466# Possible values are: HTML-CSS (which is slower, but has the best
1467# compatibility), NativeMML (i.e. MathML) and SVG.
1468# The default value is: HTML-CSS.
1469# This tag requires that the tag USE_MATHJAX is set to YES.
1470
1471MATHJAX_FORMAT = HTML-CSS
1472
1473# When MathJax is enabled you need to specify the location relative to the HTML
1474# output directory using the MATHJAX_RELPATH option. The destination directory
1475# should contain the MathJax.js script. For instance, if the mathjax directory
1476# is located at the same level as the HTML output directory, then
1477# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
1478# Content Delivery Network so you can quickly see the result without installing
1479# MathJax. However, it is strongly recommended to install a local copy of
1480# MathJax from http://www.mathjax.org before deployment.
1481# The default value is: http://cdn.mathjax.org/mathjax/latest.
1482# This tag requires that the tag USE_MATHJAX is set to YES.
1483
1484MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
1485
1486# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
1487# extension names that should be enabled during MathJax rendering. For example
1488# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
1489# This tag requires that the tag USE_MATHJAX is set to YES.
1490
1491MATHJAX_EXTENSIONS =
1492
1493# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
1494# of code that will be used on startup of the MathJax code. See the MathJax site
1495# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
1496# example see the documentation.
1497# This tag requires that the tag USE_MATHJAX is set to YES.
1498
1499MATHJAX_CODEFILE =
1500
1501# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
1502# the HTML output. The underlying search engine uses javascript and DHTML and
1503# should work on any modern browser. Note that when using HTML help
1504# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
1505# there is already a search function so this one should typically be disabled.
1506# For large projects the javascript based search engine can be slow, then
1507# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
1508# search using the keyboard; to jump to the search box use <access key> + S
1509# (what the <access key> is depends on the OS and browser, but it is typically
1510# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
1511# key> to jump into the search results window, the results can be navigated
1512# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
1513# the search. The filter options can be selected when the cursor is inside the
1514# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
1515# to select a filter and <Enter> or <escape> to activate or cancel the filter
1516# option.
1517# The default value is: YES.
1518# This tag requires that the tag GENERATE_HTML is set to YES.
1519
1520SEARCHENGINE = YES
1521
1522# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
1523# implemented using a web server instead of a web client using Javascript. There
1524# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
1525# setting. When disabled, doxygen will generate a PHP script for searching and
1526# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
1527# and searching needs to be provided by external tools. See the section
1528# "External Indexing and Searching" for details.
1529# The default value is: NO.
1530# This tag requires that the tag SEARCHENGINE is set to YES.
1531
1532SERVER_BASED_SEARCH = NO
1533
1534# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
1535# script for searching. Instead the search results are written to an XML file
1536# which needs to be processed by an external indexer. Doxygen will invoke an
1537# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
1538# search results.
1539#
1540# Doxygen ships with an example indexer ( doxyindexer) and search engine
1541# (doxysearch.cgi) which are based on the open source search engine library
1542# Xapian (see: http://xapian.org/).
1543#
1544# See the section "External Indexing and Searching" for details.
1545# The default value is: NO.
1546# This tag requires that the tag SEARCHENGINE is set to YES.
1547
1548EXTERNAL_SEARCH = NO
1549
1550# The SEARCHENGINE_URL should point to a search engine hosted by a web server
1551# which will return the search results when EXTERNAL_SEARCH is enabled.
1552#
1553# Doxygen ships with an example indexer ( doxyindexer) and search engine
1554# (doxysearch.cgi) which are based on the open source search engine library
1555# Xapian (see: http://xapian.org/). See the section "External Indexing and
1556# Searching" for details.
1557# This tag requires that the tag SEARCHENGINE is set to YES.
1558
1559SEARCHENGINE_URL =
1560
1561# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
1562# search data is written to a file for indexing by an external tool. With the
1563# SEARCHDATA_FILE tag the name of this file can be specified.
1564# The default file is: searchdata.xml.
1565# This tag requires that the tag SEARCHENGINE is set to YES.
1566
1567SEARCHDATA_FILE = searchdata.xml
1568
1569# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
1570# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
1571# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
1572# projects and redirect the results back to the right project.
1573# This tag requires that the tag SEARCHENGINE is set to YES.
1574
1575EXTERNAL_SEARCH_ID =
1576
1577# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
1578# projects other than the one defined by this configuration file, but that are
1579# all added to the same external search index. Each project needs to have a
1580# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
1581# to a relative location where the documentation can be found. The format is:
1582# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
1583# This tag requires that the tag SEARCHENGINE is set to YES.
1584
1585EXTRA_SEARCH_MAPPINGS =
1586
1587#---------------------------------------------------------------------------
1588# Configuration options related to the LaTeX output
1589#---------------------------------------------------------------------------
1590
1591# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
1592# The default value is: YES.
1593
1594GENERATE_LATEX = NO
1595
1596# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
1597# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
1598# it.
1599# The default directory is: latex.
1600# This tag requires that the tag GENERATE_LATEX is set to YES.
1601
1602LATEX_OUTPUT = latex
1603
1604# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
1605# invoked.
1606#
1607# Note that when enabling USE_PDFLATEX this option is only used for generating
1608# bitmaps for formulas in the HTML output, but not in the Makefile that is
1609# written to the output directory.
1610# The default file is: latex.
1611# This tag requires that the tag GENERATE_LATEX is set to YES.
1612
1613LATEX_CMD_NAME = latex
1614
1615# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
1616# index for LaTeX.
1617# The default file is: makeindex.
1618# This tag requires that the tag GENERATE_LATEX is set to YES.
1619
1620MAKEINDEX_CMD_NAME = makeindex
1621
1622# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
1623# documents. This may be useful for small projects and may help to save some
1624# trees in general.
1625# The default value is: NO.
1626# This tag requires that the tag GENERATE_LATEX is set to YES.
1627
1628COMPACT_LATEX = NO
1629
1630# The PAPER_TYPE tag can be used to set the paper type that is used by the
1631# printer.
1632# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
1633# 14 inches) and executive (7.25 x 10.5 inches).
1634# The default value is: a4.
1635# This tag requires that the tag GENERATE_LATEX is set to YES.
1636
1637PAPER_TYPE = a4
1638
1639# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
1640# that should be included in the LaTeX output. To get the times font for
1641# instance you can specify
1642# EXTRA_PACKAGES=times
1643# If left blank no extra packages will be included.
1644# This tag requires that the tag GENERATE_LATEX is set to YES.
1645
1646EXTRA_PACKAGES =
1647
1648# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
1649# generated LaTeX document. The header should contain everything until the first
1650# chapter. If it is left blank doxygen will generate a standard header. See
1651# section "Doxygen usage" for information on how to let doxygen write the
1652# default header to a separate file.
1653#
1654# Note: Only use a user-defined header if you know what you are doing! The
1655# following commands have a special meaning inside the header: $title,
1656# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
1657# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
1658# for the replacement values of the other commands the user is refered to
1659# HTML_HEADER.
1660# This tag requires that the tag GENERATE_LATEX is set to YES.
1661
1662LATEX_HEADER =
1663
1664# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
1665# generated LaTeX document. The footer should contain everything after the last
1666# chapter. If it is left blank doxygen will generate a standard footer. See
1667# LATEX_HEADER for more information on how to generate a default footer and what
1668# special commands can be used inside the footer.
1669#
1670# Note: Only use a user-defined footer if you know what you are doing!
1671# This tag requires that the tag GENERATE_LATEX is set to YES.
1672
1673LATEX_FOOTER =
1674
1675# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
1676# other source files which should be copied to the LATEX_OUTPUT output
1677# directory. Note that the files will be copied as-is; there are no commands or
1678# markers available.
1679# This tag requires that the tag GENERATE_LATEX is set to YES.
1680
1681LATEX_EXTRA_FILES =
1682
1683# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
1684# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
1685# contain links (just like the HTML output) instead of page references. This
1686# makes the output suitable for online browsing using a PDF viewer.
1687# The default value is: YES.
1688# This tag requires that the tag GENERATE_LATEX is set to YES.
1689
1690PDF_HYPERLINKS = YES
1691
1692# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
1693# the PDF file directly from the LaTeX files. Set this option to YES to get a
1694# higher quality PDF documentation.
1695# The default value is: YES.
1696# This tag requires that the tag GENERATE_LATEX is set to YES.
1697
1698USE_PDFLATEX = YES
1699
1700# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
1701# command to the generated LaTeX files. This will instruct LaTeX to keep running
1702# if errors occur, instead of asking the user for help. This option is also used
1703# when generating formulas in HTML.
1704# The default value is: NO.
1705# This tag requires that the tag GENERATE_LATEX is set to YES.
1706
1707LATEX_BATCHMODE = NO
1708
1709# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
1710# index chapters (such as File Index, Compound Index, etc.) in the output.
1711# The default value is: NO.
1712# This tag requires that the tag GENERATE_LATEX is set to YES.
1713
1714LATEX_HIDE_INDICES = NO
1715
1716# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
1717# code with syntax highlighting in the LaTeX output.
1718#
1719# Note that which sources are shown also depends on other settings such as
1720# SOURCE_BROWSER.
1721# The default value is: NO.
1722# This tag requires that the tag GENERATE_LATEX is set to YES.
1723
1724LATEX_SOURCE_CODE = NO
1725
1726# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
1727# bibliography, e.g. plainnat, or ieeetr. See
1728# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
1729# The default value is: plain.
1730# This tag requires that the tag GENERATE_LATEX is set to YES.
1731
1732LATEX_BIB_STYLE = plain
1733
1734#---------------------------------------------------------------------------
1735# Configuration options related to the RTF output
1736#---------------------------------------------------------------------------
1737
1738# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
1739# RTF output is optimized for Word 97 and may not look too pretty with other RTF
1740# readers/editors.
1741# The default value is: NO.
1742
1743GENERATE_RTF = NO
1744
1745# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
1746# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
1747# it.
1748# The default directory is: rtf.
1749# This tag requires that the tag GENERATE_RTF is set to YES.
1750
1751RTF_OUTPUT = rtf
1752
1753# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
1754# documents. This may be useful for small projects and may help to save some
1755# trees in general.
1756# The default value is: NO.
1757# This tag requires that the tag GENERATE_RTF is set to YES.
1758
1759COMPACT_RTF = NO
1760
1761# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
1762# contain hyperlink fields. The RTF file will contain links (just like the HTML
1763# output) instead of page references. This makes the output suitable for online
1764# browsing using Word or some other Word compatible readers that support those
1765# fields.
1766#
1767# Note: WordPad (write) and others do not support links.
1768# The default value is: NO.
1769# This tag requires that the tag GENERATE_RTF is set to YES.
1770
1771RTF_HYPERLINKS = NO
1772
1773# Load stylesheet definitions from file. Syntax is similar to doxygen's config
1774# file, i.e. a series of assignments. You only have to provide replacements,
1775# missing definitions are set to their default value.
1776#
1777# See also section "Doxygen usage" for information on how to generate the
1778# default style sheet that doxygen normally uses.
1779# This tag requires that the tag GENERATE_RTF is set to YES.
1780
1781RTF_STYLESHEET_FILE =
1782
1783# Set optional variables used in the generation of an RTF document. Syntax is
1784# similar to doxygen's config file. A template extensions file can be generated
1785# using doxygen -e rtf extensionFile.
1786# This tag requires that the tag GENERATE_RTF is set to YES.
1787
1788RTF_EXTENSIONS_FILE =
1789
1790#---------------------------------------------------------------------------
1791# Configuration options related to the man page output
1792#---------------------------------------------------------------------------
1793
1794# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
1795# classes and files.
1796# The default value is: NO.
1797
1798GENERATE_MAN = NO
1799
1800# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
1801# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
1802# it. A directory man3 will be created inside the directory specified by
1803# MAN_OUTPUT.
1804# The default directory is: man.
1805# This tag requires that the tag GENERATE_MAN is set to YES.
1806
1807MAN_OUTPUT = man
1808
1809# The MAN_EXTENSION tag determines the extension that is added to the generated
1810# man pages. In case the manual section does not start with a number, the number
1811# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
1812# optional.
1813# The default value is: .3.
1814# This tag requires that the tag GENERATE_MAN is set to YES.
1815
1816MAN_EXTENSION = .3
1817
1818# The MAN_SUBDIR tag determines the name of the directory created within
1819# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
1820# MAN_EXTENSION with the initial . removed.
1821# This tag requires that the tag GENERATE_MAN is set to YES.
1822
1823MAN_SUBDIR =
1824
1825# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
1826# will generate one additional man file for each entity documented in the real
1827# man page(s). These additional files only source the real man page, but without
1828# them the man command would be unable to find the correct page.
1829# The default value is: NO.
1830# This tag requires that the tag GENERATE_MAN is set to YES.
1831
1832MAN_LINKS = NO
1833
1834#---------------------------------------------------------------------------
1835# Configuration options related to the XML output
1836#---------------------------------------------------------------------------
1837
1838# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
1839# captures the structure of the code including all documentation.
1840# The default value is: NO.
1841
1842GENERATE_XML = NO
1843
1844# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
1845# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
1846# it.
1847# The default directory is: xml.
1848# This tag requires that the tag GENERATE_XML is set to YES.
1849
1850XML_OUTPUT = xml
1851
1852# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
1853# listings (including syntax highlighting and cross-referencing information) to
1854# the XML output. Note that enabling this will significantly increase the size
1855# of the XML output.
1856# The default value is: YES.
1857# This tag requires that the tag GENERATE_XML is set to YES.
1858
1859XML_PROGRAMLISTING = YES
1860
1861#---------------------------------------------------------------------------
1862# Configuration options related to the DOCBOOK output
1863#---------------------------------------------------------------------------
1864
1865# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
1866# that can be used to generate PDF.
1867# The default value is: NO.
1868
1869GENERATE_DOCBOOK = NO
1870
1871# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
1872# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
1873# front of it.
1874# The default directory is: docbook.
1875# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
1876
1877DOCBOOK_OUTPUT = docbook
1878
1879# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
1880# program listings (including syntax highlighting and cross-referencing
1881# information) to the DOCBOOK output. Note that enabling this will significantly
1882# increase the size of the DOCBOOK output.
1883# The default value is: NO.
1884# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
1885
1886DOCBOOK_PROGRAMLISTING = NO
1887
1888#---------------------------------------------------------------------------
1889# Configuration options for the AutoGen Definitions output
1890#---------------------------------------------------------------------------
1891
1892# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
1893# Definitions (see http://autogen.sf.net) file that captures the structure of
1894# the code including all documentation. Note that this feature is still
1895# experimental and incomplete at the moment.
1896# The default value is: NO.
1897
1898GENERATE_AUTOGEN_DEF = NO
1899
1900#---------------------------------------------------------------------------
1901# Configuration options related to the Perl module output
1902#---------------------------------------------------------------------------
1903
1904# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
1905# file that captures the structure of the code including all documentation.
1906#
1907# Note that this feature is still experimental and incomplete at the moment.
1908# The default value is: NO.
1909
1910GENERATE_PERLMOD = NO
1911
1912# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
1913# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
1914# output from the Perl module output.
1915# The default value is: NO.
1916# This tag requires that the tag GENERATE_PERLMOD is set to YES.
1917
1918PERLMOD_LATEX = NO
1919
1920# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
1921# formatted so it can be parsed by a human reader. This is useful if you want to
1922# understand what is going on. On the other hand, if this tag is set to NO the
1923# size of the Perl module output will be much smaller and Perl will parse it
1924# just the same.
1925# The default value is: YES.
1926# This tag requires that the tag GENERATE_PERLMOD is set to YES.
1927
1928PERLMOD_PRETTY = YES
1929
1930# The names of the make variables in the generated doxyrules.make file are
1931# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
1932# so different doxyrules.make files included by the same Makefile don't
1933# overwrite each other's variables.
1934# This tag requires that the tag GENERATE_PERLMOD is set to YES.
1935
1936PERLMOD_MAKEVAR_PREFIX =
1937
1938#---------------------------------------------------------------------------
1939# Configuration options related to the preprocessor
1940#---------------------------------------------------------------------------
1941
1942# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
1943# C-preprocessor directives found in the sources and include files.
1944# The default value is: YES.
1945
1946ENABLE_PREPROCESSING = YES
1947
1948# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
1949# in the source code. If set to NO only conditional compilation will be
1950# performed. Macro expansion can be done in a controlled way by setting
1951# EXPAND_ONLY_PREDEF to YES.
1952# The default value is: NO.
1953# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
1954
1955MACRO_EXPANSION = NO
1956
1957# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
1958# the macro expansion is limited to the macros specified with the PREDEFINED and
1959# EXPAND_AS_DEFINED tags.
1960# The default value is: NO.
1961# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
1962
1963EXPAND_ONLY_PREDEF = NO
1964
1965# If the SEARCH_INCLUDES tag is set to YES the includes files in the
1966# INCLUDE_PATH will be searched if a #include is found.
1967# The default value is: YES.
1968# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
1969
1970SEARCH_INCLUDES = YES
1971
1972# The INCLUDE_PATH tag can be used to specify one or more directories that
1973# contain include files that are not input files but should be processed by the
1974# preprocessor.
1975# This tag requires that the tag SEARCH_INCLUDES is set to YES.
1976
1977INCLUDE_PATH =
1978
1979# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
1980# patterns (like *.h and *.hpp) to filter out the header-files in the
1981# directories. If left blank, the patterns specified with FILE_PATTERNS will be
1982# used.
1983# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
1984
1985INCLUDE_FILE_PATTERNS =
1986
1987# The PREDEFINED tag can be used to specify one or more macro names that are
1988# defined before the preprocessor is started (similar to the -D option of e.g.
1989# gcc). The argument of the tag is a list of macros of the form: name or
1990# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
1991# is assumed. To prevent a macro definition from being undefined via #undef or
1992# recursively expanded use the := operator instead of the = operator.
1993# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
1994
1995PREDEFINED =
1996
1997# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
1998# tag can be used to specify a list of macro names that should be expanded. The
1999# macro definition that is found in the sources will be used. Use the PREDEFINED
2000# tag if you want to use a different macro definition that overrules the
2001# definition found in the source code.
2002# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
2003
2004EXPAND_AS_DEFINED =
2005
2006# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
2007# remove all references to function-like macros that are alone on a line, have
2008# an all uppercase name, and do not end with a semicolon. Such function macros
2009# are typically used for boiler-plate code, and will confuse the parser if not
2010# removed.
2011# The default value is: YES.
2012# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
2013
2014SKIP_FUNCTION_MACROS = YES
2015
2016#---------------------------------------------------------------------------
2017# Configuration options related to external references
2018#---------------------------------------------------------------------------
2019
2020# The TAGFILES tag can be used to specify one or more tag files. For each tag
2021# file the location of the external documentation should be added. The format of
2022# a tag file without this location is as follows:
2023# TAGFILES = file1 file2 ...
2024# Adding location for the tag files is done as follows:
2025# TAGFILES = file1=loc1 "file2 = loc2" ...
2026# where loc1 and loc2 can be relative or absolute paths or URLs. See the
2027# section "Linking to external documentation" for more information about the use
2028# of tag files.
2029# Note: Each tag file must have a unique name (where the name does NOT include
2030# the path). If a tag file is not located in the directory in which doxygen is
2031# run, you must also specify the path to the tagfile here.
2032
2033TAGFILES =
2034
2035# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
2036# tag file that is based on the input files it reads. See section "Linking to
2037# external documentation" for more information about the usage of tag files.
2038
2039GENERATE_TAGFILE =
2040
2041# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
2042# class index. If set to NO only the inherited external classes will be listed.
2043# The default value is: NO.
2044
2045ALLEXTERNALS = NO
2046
2047# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
2048# the modules index. If set to NO, only the current project's groups will be
2049# listed.
2050# The default value is: YES.
2051
2052EXTERNAL_GROUPS = YES
2053
2054# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
2055# the related pages index. If set to NO, only the current project's pages will
2056# be listed.
2057# The default value is: YES.
2058
2059EXTERNAL_PAGES = YES
2060
2061# The PERL_PATH should be the absolute path and name of the perl script
2062# interpreter (i.e. the result of 'which perl').
2063# The default file (with absolute path) is: /usr/bin/perl.
2064
2065PERL_PATH = /usr/bin/perl
2066
2067#---------------------------------------------------------------------------
2068# Configuration options related to the dot tool
2069#---------------------------------------------------------------------------
2070
2071# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
2072# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
2073# NO turns the diagrams off. Note that this option also works with HAVE_DOT
2074# disabled, but it is recommended to install and use dot, since it yields more
2075# powerful graphs.
2076# The default value is: YES.
2077
2078CLASS_DIAGRAMS = YES
2079
2080# You can define message sequence charts within doxygen comments using the \msc
2081# command. Doxygen will then run the mscgen tool (see:
2082# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
2083# documentation. The MSCGEN_PATH tag allows you to specify the directory where
2084# the mscgen tool resides. If left empty the tool is assumed to be found in the
2085# default search path.
2086
2087MSCGEN_PATH =
2088
2089# You can include diagrams made with dia in doxygen documentation. Doxygen will
2090# then run dia to produce the diagram and insert it in the documentation. The
2091# DIA_PATH tag allows you to specify the directory where the dia binary resides.
2092# If left empty dia is assumed to be found in the default search path.
2093
2094DIA_PATH =
2095
2096# If set to YES, the inheritance and collaboration graphs will hide inheritance
2097# and usage relations if the target is undocumented or is not a class.
2098# The default value is: YES.
2099
2100HIDE_UNDOC_RELATIONS = YES
2101
2102# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
2103# available from the path. This tool is part of Graphviz (see:
2104# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
2105# Bell Labs. The other options in this section have no effect if this option is
2106# set to NO
2107# The default value is: NO.
2108
2109HAVE_DOT = NO
2110
2111# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
2112# to run in parallel. When set to 0 doxygen will base this on the number of
2113# processors available in the system. You can set it explicitly to a value
2114# larger than 0 to get control over the balance between CPU load and processing
2115# speed.
2116# Minimum value: 0, maximum value: 32, default value: 0.
2117# This tag requires that the tag HAVE_DOT is set to YES.
2118
2119DOT_NUM_THREADS = 0
2120
2121# When you want a differently looking font in the dot files that doxygen
2122# generates you can specify the font name using DOT_FONTNAME. You need to make
2123# sure dot is able to find the font, which can be done by putting it in a
2124# standard location or by setting the DOTFONTPATH environment variable or by
2125# setting DOT_FONTPATH to the directory containing the font.
2126# The default value is: Helvetica.
2127# This tag requires that the tag HAVE_DOT is set to YES.
2128
2129DOT_FONTNAME = Helvetica
2130
2131# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
2132# dot graphs.
2133# Minimum value: 4, maximum value: 24, default value: 10.
2134# This tag requires that the tag HAVE_DOT is set to YES.
2135
2136DOT_FONTSIZE = 10
2137
2138# By default doxygen will tell dot to use the default font as specified with
2139# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
2140# the path where dot can find it using this tag.
2141# This tag requires that the tag HAVE_DOT is set to YES.
2142
2143DOT_FONTPATH =
2144
2145# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
2146# each documented class showing the direct and indirect inheritance relations.
2147# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
2148# The default value is: YES.
2149# This tag requires that the tag HAVE_DOT is set to YES.
2150
2151CLASS_GRAPH = YES
2152
2153# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
2154# graph for each documented class showing the direct and indirect implementation
2155# dependencies (inheritance, containment, and class references variables) of the
2156# class with other documented classes.
2157# The default value is: YES.
2158# This tag requires that the tag HAVE_DOT is set to YES.
2159
2160COLLABORATION_GRAPH = YES
2161
2162# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
2163# groups, showing the direct groups dependencies.
2164# The default value is: YES.
2165# This tag requires that the tag HAVE_DOT is set to YES.
2166
2167GROUP_GRAPHS = YES
2168
2169# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
2170# collaboration diagrams in a style similar to the OMG's Unified Modeling
2171# Language.
2172# The default value is: NO.
2173# This tag requires that the tag HAVE_DOT is set to YES.
2174
2175UML_LOOK = NO
2176
2177# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
2178# class node. If there are many fields or methods and many nodes the graph may
2179# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
2180# number of items for each type to make the size more manageable. Set this to 0
2181# for no limit. Note that the threshold may be exceeded by 50% before the limit
2182# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
2183# but if the number exceeds 15, the total amount of fields shown is limited to
2184# 10.
2185# Minimum value: 0, maximum value: 100, default value: 10.
2186# This tag requires that the tag HAVE_DOT is set to YES.
2187
2188UML_LIMIT_NUM_FIELDS = 10
2189
2190# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
2191# collaboration graphs will show the relations between templates and their
2192# instances.
2193# The default value is: NO.
2194# This tag requires that the tag HAVE_DOT is set to YES.
2195
2196TEMPLATE_RELATIONS = NO
2197
2198# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
2199# YES then doxygen will generate a graph for each documented file showing the
2200# direct and indirect include dependencies of the file with other documented
2201# files.
2202# The default value is: YES.
2203# This tag requires that the tag HAVE_DOT is set to YES.
2204
2205INCLUDE_GRAPH = YES
2206
2207# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
2208# set to YES then doxygen will generate a graph for each documented file showing
2209# the direct and indirect include dependencies of the file with other documented
2210# files.
2211# The default value is: YES.
2212# This tag requires that the tag HAVE_DOT is set to YES.
2213
2214INCLUDED_BY_GRAPH = YES
2215
2216# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
2217# dependency graph for every global function or class method.
2218#
2219# Note that enabling this option will significantly increase the time of a run.
2220# So in most cases it will be better to enable call graphs for selected
2221# functions only using the \callgraph command.
2222# The default value is: NO.
2223# This tag requires that the tag HAVE_DOT is set to YES.
2224
2225CALL_GRAPH = NO
2226
2227# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
2228# dependency graph for every global function or class method.
2229#
2230# Note that enabling this option will significantly increase the time of a run.
2231# So in most cases it will be better to enable caller graphs for selected
2232# functions only using the \callergraph command.
2233# The default value is: NO.
2234# This tag requires that the tag HAVE_DOT is set to YES.
2235
2236CALLER_GRAPH = NO
2237
2238# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
2239# hierarchy of all classes instead of a textual one.
2240# The default value is: YES.
2241# This tag requires that the tag HAVE_DOT is set to YES.
2242
2243GRAPHICAL_HIERARCHY = YES
2244
2245# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
2246# dependencies a directory has on other directories in a graphical way. The
2247# dependency relations are determined by the #include relations between the
2248# files in the directories.
2249# The default value is: YES.
2250# This tag requires that the tag HAVE_DOT is set to YES.
2251
2252DIRECTORY_GRAPH = YES
2253
2254# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
2255# generated by dot.
2256# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
2257# to make the SVG files visible in IE 9+ (other browsers do not have this
2258# requirement).
2259# Possible values are: png, jpg, gif and svg.
2260# The default value is: png.
2261# This tag requires that the tag HAVE_DOT is set to YES.
2262
2263DOT_IMAGE_FORMAT = png
2264
2265# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
2266# enable generation of interactive SVG images that allow zooming and panning.
2267#
2268# Note that this requires a modern browser other than Internet Explorer. Tested
2269# and working are Firefox, Chrome, Safari, and Opera.
2270# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
2271# the SVG files visible. Older versions of IE do not have SVG support.
2272# The default value is: NO.
2273# This tag requires that the tag HAVE_DOT is set to YES.
2274
2275INTERACTIVE_SVG = NO
2276
2277# The DOT_PATH tag can be used to specify the path where the dot tool can be
2278# found. If left blank, it is assumed the dot tool can be found in the path.
2279# This tag requires that the tag HAVE_DOT is set to YES.
2280
2281DOT_PATH =
2282
2283# The DOTFILE_DIRS tag can be used to specify one or more directories that
2284# contain dot files that are included in the documentation (see the \dotfile
2285# command).
2286# This tag requires that the tag HAVE_DOT is set to YES.
2287
2288DOTFILE_DIRS =
2289
2290# The MSCFILE_DIRS tag can be used to specify one or more directories that
2291# contain msc files that are included in the documentation (see the \mscfile
2292# command).
2293
2294MSCFILE_DIRS =
2295
2296# The DIAFILE_DIRS tag can be used to specify one or more directories that
2297# contain dia files that are included in the documentation (see the \diafile
2298# command).
2299
2300DIAFILE_DIRS =
2301
2302# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
2303# path where java can find the plantuml.jar file. If left blank, it is assumed
2304# PlantUML is not used or called during a preprocessing step. Doxygen will
2305# generate a warning when it encounters a \startuml command in this case and
2306# will not generate output for the diagram.
2307# This tag requires that the tag HAVE_DOT is set to YES.
2308
2309PLANTUML_JAR_PATH =
2310
2311# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
2312# that will be shown in the graph. If the number of nodes in a graph becomes
2313# larger than this value, doxygen will truncate the graph, which is visualized
2314# by representing a node as a red box. Note that doxygen if the number of direct
2315# children of the root node in a graph is already larger than
2316# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
2317# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
2318# Minimum value: 0, maximum value: 10000, default value: 50.
2319# This tag requires that the tag HAVE_DOT is set to YES.
2320
2321DOT_GRAPH_MAX_NODES = 50
2322
2323# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
2324# generated by dot. A depth value of 3 means that only nodes reachable from the
2325# root by following a path via at most 3 edges will be shown. Nodes that lay
2326# further from the root node will be omitted. Note that setting this option to 1
2327# or 2 may greatly reduce the computation time needed for large code bases. Also
2328# note that the size of a graph can be further restricted by
2329# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
2330# Minimum value: 0, maximum value: 1000, default value: 0.
2331# This tag requires that the tag HAVE_DOT is set to YES.
2332
2333MAX_DOT_GRAPH_DEPTH = 0
2334
2335# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
2336# background. This is disabled by default, because dot on Windows does not seem
2337# to support this out of the box.
2338#
2339# Warning: Depending on the platform used, enabling this option may lead to
2340# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
2341# read).
2342# The default value is: NO.
2343# This tag requires that the tag HAVE_DOT is set to YES.
2344
2345DOT_TRANSPARENT = NO
2346
2347# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
2348# files in one run (i.e. multiple -o and -T options on the command line). This
2349# makes dot run faster, but since only newer versions of dot (>1.8.10) support
2350# this, this feature is disabled by default.
2351# The default value is: NO.
2352# This tag requires that the tag HAVE_DOT is set to YES.
2353
2354DOT_MULTI_TARGETS = NO
2355
2356# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
2357# explaining the meaning of the various boxes and arrows in the dot generated
2358# graphs.
2359# The default value is: YES.
2360# This tag requires that the tag HAVE_DOT is set to YES.
2361
2362GENERATE_LEGEND = YES
2363
2364# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
2365# files that are used to generate the various graphs.
2366# The default value is: YES.
2367# This tag requires that the tag HAVE_DOT is set to YES.
2368
2369DOT_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 @@
1set(SRCS
2 inih/ini.c
3 inih/cpp/INIReader.cpp
4 )
5set(HEADERS
6 inih/ini.h
7 inih/cpp/INIReader.h
8 )
9
10create_directory_groups(${SRCS} ${HEADERS})
11add_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 @@
1set(SRCS 1set(SRCS
2 emu_window/emu_window_glfw.cpp 2 emu_window/emu_window_glfw.cpp
3 citra.cpp 3 citra.cpp
4 config.cpp
4 ) 5 )
5set(HEADERS 6set(HEADERS
6 emu_window/emu_window_glfw.h 7 emu_window/emu_window_glfw.h
8 config.h
9 default_ini.h
7 resource.h 10 resource.h
8 ) 11 )
9 12
@@ -16,7 +19,7 @@ endif()
16 19
17add_executable(citra ${SRCS} ${HEADERS}) 20add_executable(citra ${SRCS} ${HEADERS})
18target_link_libraries(citra core common video_core) 21target_link_libraries(citra core common video_core)
19target_link_libraries(citra ${OPENGL_gl_LIBRARY} ${GLFW_LIBRARIES}) 22target_link_libraries(citra ${OPENGL_gl_LIBRARY} ${GLFW_LIBRARIES} inih)
20 23
21if (APPLE) 24if (APPLE)
22 target_link_libraries(citra iconv pthread ${COREFOUNDATION_LIBRARY}) 25 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 @@
4 4
5#include "common/common.h" 5#include "common/common.h"
6#include "common/log_manager.h" 6#include "common/log_manager.h"
7#include "common/file_util.h"
8 7
9#include "core/system.h" 8#include "core/system.h"
10#include "core/core.h" 9#include "core/core.h"
11#include "core/loader/loader.h" 10#include "core/loader/loader.h"
12 11
12#include "citra/config.h"
13#include "citra/emu_window/emu_window_glfw.h" 13#include "citra/emu_window/emu_window_glfw.h"
14 14
15/// Application entry point 15/// Application entry point
@@ -21,17 +21,20 @@ int __cdecl main(int argc, char **argv) {
21 return -1; 21 return -1;
22 } 22 }
23 23
24 Config config;
25
24 std::string boot_filename = argv[1]; 26 std::string boot_filename = argv[1];
25 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; 27 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW;
26 28
27 System::Init(emu_window); 29 System::Init(emu_window);
28 30
29 if (Loader::ResultStatus::Success != Loader::LoadFile(boot_filename)) { 31 Loader::ResultStatus load_result = Loader::LoadFile(boot_filename);
30 ERROR_LOG(BOOT, "Failed to load ROM!"); 32 if (Loader::ResultStatus::Success != load_result) {
33 ERROR_LOG(BOOT, "Failed to load ROM (Error %i)!", load_result);
31 return -1; 34 return -1;
32 } 35 }
33 36
34 while(true) { 37 while (emu_window->IsOpen()) {
35 Core::RunLoop(); 38 Core::RunLoop();
36 } 39 }
37 40
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <GLFW/glfw3.h>
6
7#include "citra/default_ini.h"
8#include "common/file_util.h"
9#include "core/settings.h"
10#include "core/core.h"
11
12#include "config.h"
13
14Config::Config() {
15 // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
16 glfw_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "glfw-config.ini";
17 glfw_config = new INIReader(glfw_config_loc);
18
19 Reload();
20}
21
22bool Config::LoadINI(INIReader* config, const char* location, const std::string& default_contents, bool retry) {
23 if (config->ParseError() < 0) {
24 if (retry) {
25 ERROR_LOG(CONFIG, "Failed to load %s. Creating file from defaults...", location);
26 FileUtil::CreateFullPath(location);
27 FileUtil::WriteStringToFile(true, default_contents, location);
28 *config = INIReader(location); // Reopen file
29
30 return LoadINI(config, location, default_contents, false);
31 }
32 ERROR_LOG(CONFIG, "Failed.");
33 return false;
34 }
35 INFO_LOG(CONFIG, "Successfully loaded %s", location);
36 return true;
37}
38
39void Config::ReadControls() {
40 Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A);
41 Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S);
42 Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z);
43 Settings::values.pad_y_key = glfw_config->GetInteger("Controls", "pad_y", GLFW_KEY_X);
44 Settings::values.pad_l_key = glfw_config->GetInteger("Controls", "pad_l", GLFW_KEY_Q);
45 Settings::values.pad_r_key = glfw_config->GetInteger("Controls", "pad_r", GLFW_KEY_W);
46 Settings::values.pad_start_key = glfw_config->GetInteger("Controls", "pad_start", GLFW_KEY_M);
47 Settings::values.pad_select_key = glfw_config->GetInteger("Controls", "pad_select", GLFW_KEY_N);
48 Settings::values.pad_home_key = glfw_config->GetInteger("Controls", "pad_home", GLFW_KEY_B);
49 Settings::values.pad_dup_key = glfw_config->GetInteger("Controls", "pad_dup", GLFW_KEY_T);
50 Settings::values.pad_ddown_key = glfw_config->GetInteger("Controls", "pad_ddown", GLFW_KEY_G);
51 Settings::values.pad_dleft_key = glfw_config->GetInteger("Controls", "pad_dleft", GLFW_KEY_F);
52 Settings::values.pad_dright_key = glfw_config->GetInteger("Controls", "pad_dright", GLFW_KEY_H);
53 Settings::values.pad_sup_key = glfw_config->GetInteger("Controls", "pad_sup", GLFW_KEY_UP);
54 Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN);
55 Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT);
56 Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT);
57}
58
59void Config::ReadCore() {
60 Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter);
61 Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 60);
62}
63
64void Config::ReadData() {
65 Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true);
66}
67
68void Config::Reload() {
69 LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file);
70 ReadControls();
71 ReadCore();
72 ReadData();
73}
74
75Config::~Config() {
76 delete glfw_config;
77}
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8
9#include <inih/cpp/INIReader.h>
10
11#include "common/common_types.h"
12
13class Config {
14 INIReader* glfw_config;
15 std::string glfw_config_loc;
16
17 bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true);
18 void ReadControls();
19 void ReadCore();
20 void ReadData();
21public:
22 Config();
23 ~Config();
24
25 void Reload();
26};
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace DefaultINI {
8
9const char* glfw_config_file = R"(
10[Controls]
11pad_start =
12pad_select =
13pad_home =
14pad_dup =
15pad_ddown =
16pad_dleft =
17pad_dright =
18pad_a =
19pad_b =
20pad_x =
21pad_y =
22pad_r =
23pad_l =
24pad_sup =
25pad_sdown =
26pad_sleft =
27pad_sright =
28
29[Core]
30cpu_core = ## 0: Interpreter (default), 1: FastInterpreter (experimental)
31gpu_refresh_rate = ## 60 (default)
32
33[Data Storage]
34use_virtual_sd =
35)";
36
37}
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 @@
6 6
7#include "video_core/video_core.h" 7#include "video_core/video_core.h"
8 8
9#include "core/settings.h"
10
9#include "citra/emu_window/emu_window_glfw.h" 11#include "citra/emu_window/emu_window_glfw.h"
10 12
11static void OnKeyEvent(GLFWwindow* win, int key, int action) { 13/// Called by GLFW when a key event occurs
12 // TODO(bunnei): ImplementMe 14void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) {
15
16 if (!VideoCore::g_emu_window) {
17 return;
18 }
19
20 int keyboard_id = ((EmuWindow_GLFW*)VideoCore::g_emu_window)->keyboard_id;
21
22 if (action == GLFW_PRESS) {
23 EmuWindow::KeyPressed({key, keyboard_id});
24 }
25
26 if (action == GLFW_RELEASE) {
27 EmuWindow::KeyReleased({key, keyboard_id});
28 }
29 HID_User::PadUpdateComplete();
13} 30}
14 31
15static void OnWindowSizeEvent(GLFWwindow* win, int width, int height) { 32/// Whether the window is still open, and a close request hasn't yet been sent
16 EmuWindow_GLFW* emu_window = (EmuWindow_GLFW*)glfwGetWindowUserPointer(win); 33const bool EmuWindow_GLFW::IsOpen() {
17 emu_window->SetClientAreaWidth(width); 34 return glfwWindowShouldClose(m_render_window) == 0;
18 emu_window->SetClientAreaHeight(height);
19} 35}
20 36
21/// EmuWindow_GLFW constructor 37/// EmuWindow_GLFW constructor
22EmuWindow_GLFW::EmuWindow_GLFW() { 38EmuWindow_GLFW::EmuWindow_GLFW() {
39 keyboard_id = KeyMap::NewDeviceId();
40
41 ReloadSetKeymaps();
42
23 // Initialize the window 43 // Initialize the window
24 if(glfwInit() != GL_TRUE) { 44 if(glfwInit() != GL_TRUE) {
25 printf("Failed to initialize GLFW! Exiting..."); 45 printf("Failed to initialize GLFW! Exiting...");
@@ -27,12 +47,9 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
27 } 47 }
28 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 48 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
29 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 49 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
30
31#if EMU_PLATFORM == PLATFORM_MACOSX
32 // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context. 50 // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context.
33 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 51 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
34 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 52 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
35#endif
36 53
37 m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, 54 m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth,
38 (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), 55 (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight),
@@ -45,8 +62,7 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
45 62
46 // Setup callbacks 63 // Setup callbacks
47 glfwSetWindowUserPointer(m_render_window, this); 64 glfwSetWindowUserPointer(m_render_window, this);
48 //glfwSetKeyCallback(m_render_window, OnKeyEvent); 65 glfwSetKeyCallback(m_render_window, OnKeyEvent);
49 //glfwSetWindowSizeCallback(m_render_window, OnWindowSizeEvent);
50 66
51 DoneCurrent(); 67 DoneCurrent();
52} 68}
@@ -75,3 +91,22 @@ void EmuWindow_GLFW::MakeCurrent() {
75void EmuWindow_GLFW::DoneCurrent() { 91void EmuWindow_GLFW::DoneCurrent() {
76 glfwMakeContextCurrent(NULL); 92 glfwMakeContextCurrent(NULL);
77} 93}
94
95void EmuWindow_GLFW::ReloadSetKeymaps() {
96 KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A);
97 KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B);
98 KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT);
99 KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START);
100 KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT);
101 KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT);
102 KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP);
103 KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN);
104 KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R);
105 KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L);
106 KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X);
107 KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y);
108 KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT);
109 KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT);
110 KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP);
111 KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN);
112}
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:
14 ~EmuWindow_GLFW(); 14 ~EmuWindow_GLFW();
15 15
16 /// Swap buffers to display the next frame 16 /// Swap buffers to display the next frame
17 void SwapBuffers(); 17 void SwapBuffers() override;
18 18
19 /// Polls window events 19 /// Polls window events
20 void PollEvents(); 20 void PollEvents() override;
21 21
22 /// Makes the graphics context current for the caller thread 22 /// Makes the graphics context current for the caller thread
23 void MakeCurrent(); 23 void MakeCurrent() override;
24 24
25 /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread 25 /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
26 void DoneCurrent(); 26 void DoneCurrent() override;
27 27
28 GLFWwindow* m_render_window; ///< Internal GLFW render window 28 static void OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods);
29
30 /// Whether the window is still open, and a close request hasn't yet been sent
31 const bool IsOpen();
32
33 void ReloadSetKeymaps() override;
29 34
30private: 35private:
36 GLFWwindow* m_render_window; ///< Internal GLFW render window
31 37
38 /// Device id of keyboard for use with KeyMap
39 int keyboard_id;
32}; 40};
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)
4set(SRCS 4set(SRCS
5 config/controller_config.cpp 5 config/controller_config.cpp
6 config/controller_config_util.cpp 6 config/controller_config_util.cpp
7 config.cpp
7 debugger/callstack.cpp 8 debugger/callstack.cpp
8 debugger/disassembler.cpp 9 debugger/disassembler.cpp
9 debugger/graphics.cpp 10 debugger/graphics.cpp
@@ -18,6 +19,7 @@ set(SRCS
18set(HEADERS 19set(HEADERS
19 config/controller_config.hxx 20 config/controller_config.hxx
20 config/controller_config_util.hxx 21 config/controller_config_util.hxx
22 config.h
21 debugger/callstack.hxx 23 debugger/callstack.hxx
22 debugger/disassembler.hxx 24 debugger/disassembler.hxx
23 debugger/graphics.hxx 25 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 @@
6#include "bootmanager.hxx" 6#include "bootmanager.hxx"
7 7
8#include "core/core.h" 8#include "core/core.h"
9#include "core/loader/loader.h" 9#include "core/settings.h"
10#include "core/hw/hw.h"
11 10
12#include "video_core/video_core.h" 11#include "video_core/video_core.h"
13 12
14#include "version.h" 13#include "citra_qt/version.h"
15 14
16#define APP_NAME "citra" 15#define APP_NAME "citra"
17#define APP_VERSION "0.1-" VERSION 16#define APP_VERSION "0.1-" VERSION
@@ -19,9 +18,8 @@
19#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" 18#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
20 19
21EmuThread::EmuThread(GRenderWindow* render_window) : 20EmuThread::EmuThread(GRenderWindow* render_window) :
22 exec_cpu_step(false), cpu_running(false), 21 filename(""), exec_cpu_step(false), cpu_running(false),
23 render_window(render_window), filename(""), 22 stop_run(false), render_window(render_window)
24 stop_run(false)
25{ 23{
26} 24}
27 25
@@ -35,19 +33,16 @@ void EmuThread::run()
35 stop_run = false; 33 stop_run = false;
36 while (!stop_run) 34 while (!stop_run)
37 { 35 {
38 for (int tight_loop = 0; tight_loop < 10000; ++tight_loop) 36 if (cpu_running)
39 { 37 {
40 if (cpu_running || exec_cpu_step) 38 Core::RunLoop();
41 { 39 }
42 if (exec_cpu_step) 40 else if (exec_cpu_step)
43 exec_cpu_step = false; 41 {
44 42 exec_cpu_step = false;
45 Core::SingleStep(); 43 Core::SingleStep();
46 if (!cpu_running) { 44 emit CPUStepped();
47 emit CPUStepped(); 45 yieldCurrentThread();
48 yieldCurrentThread();
49 }
50 }
51 } 46 }
52 } 47 }
53 render_window->moveContext(); 48 render_window->moveContext();
@@ -92,10 +87,10 @@ public:
92 parent_ = parent; 87 parent_ = parent;
93 } 88 }
94 89
95 void paintEvent(QPaintEvent* ev) 90 void paintEvent(QPaintEvent* ev) override
96 { 91 {
97 } 92 }
98 void resizeEvent(QResizeEvent* ev) { 93 void resizeEvent(QResizeEvent* ev) override {
99 parent_->SetClientAreaWidth(size().width()); 94 parent_->SetClientAreaWidth(size().width());
100 parent_->SetClientAreaHeight(size().height()); 95 parent_->SetClientAreaHeight(size().height());
101 } 96 }
@@ -103,20 +98,22 @@ private:
103 GRenderWindow* parent_; 98 GRenderWindow* parent_;
104}; 99};
105 100
106
107EmuThread& GRenderWindow::GetEmuThread() 101EmuThread& GRenderWindow::GetEmuThread()
108{ 102{
109 return emu_thread; 103 return emu_thread;
110} 104}
111 105
112GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this) 106GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0)
113{ 107{
108 keyboard_id = KeyMap::NewDeviceId();
109 ReloadSetKeymaps();
110
114 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose 111 // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose
115 QGLFormat fmt; 112 QGLFormat fmt;
116 fmt.setProfile(QGLFormat::CoreProfile);
117 fmt.setVersion(3,2); 113 fmt.setVersion(3,2);
118 fmt.setSampleBuffers(true); 114 fmt.setProfile(QGLFormat::CoreProfile);
119 fmt.setSamples(4); 115 // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X
116 fmt.setOption(QGL::NoDeprecatedFunctions);
120 117
121 child = new GGLWidgetInternal(fmt, this); 118 child = new GGLWidgetInternal(fmt, this);
122 QBoxLayout* layout = new QHBoxLayout(this); 119 QBoxLayout* layout = new QHBoxLayout(this);
@@ -209,27 +206,33 @@ QByteArray GRenderWindow::saveGeometry()
209 206
210void GRenderWindow::keyPressEvent(QKeyEvent* event) 207void GRenderWindow::keyPressEvent(QKeyEvent* event)
211{ 208{
212 /* 209 EmuWindow::KeyPressed({event->key(), keyboard_id});
213 bool key_processed = false; 210 HID_User::PadUpdateComplete();
214 for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel)
215 if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED))
216 key_processed = true;
217
218 if (!key_processed)
219 QWidget::keyPressEvent(event);
220 */
221} 211}
222 212
223void GRenderWindow::keyReleaseEvent(QKeyEvent* event) 213void GRenderWindow::keyReleaseEvent(QKeyEvent* event)
224{ 214{
225 /* 215 EmuWindow::KeyReleased({event->key(), keyboard_id});
226 bool key_processed = false; 216 HID_User::PadUpdateComplete();
227 for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) 217}
228 if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::RELEASED)) 218
229 key_processed = true; 219void GRenderWindow::ReloadSetKeymaps()
230 220{
231 if (!key_processed) 221 KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A);
232 QWidget::keyPressEvent(event); 222 KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B);
233 */ 223 KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT);
224 KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START);
225 KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT);
226 KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT);
227 KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP);
228 KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN);
229 KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R);
230 KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L);
231 KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X);
232 KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y);
233 KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT);
234 KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT);
235 KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP);
236 KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN);
234} 237}
235 238
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:
25 * 25 *
26 * @warning Only call when not running! 26 * @warning Only call when not running!
27 */ 27 */
28 void run(); 28 void run() override;
29 29
30 /** 30 /**
31 * Allow the CPU to process a single instruction (if cpu is not running) 31 * Allow the CPU to process a single instruction (if cpu is not running)
@@ -89,13 +89,13 @@ public:
89 GRenderWindow(QWidget* parent = NULL); 89 GRenderWindow(QWidget* parent = NULL);
90 ~GRenderWindow(); 90 ~GRenderWindow();
91 91
92 void closeEvent(QCloseEvent*); 92 void closeEvent(QCloseEvent*) override;
93 93
94 // EmuWindow implementation 94 // EmuWindow implementation
95 void SwapBuffers(); 95 void SwapBuffers() override;
96 void MakeCurrent(); 96 void MakeCurrent() override;
97 void DoneCurrent(); 97 void DoneCurrent() override;
98 void PollEvents(); 98 void PollEvents() override;
99 99
100 void BackupGeometry(); 100 void BackupGeometry();
101 void RestoreGeometry(); 101 void RestoreGeometry();
@@ -104,8 +104,10 @@ public:
104 104
105 EmuThread& GetEmuThread(); 105 EmuThread& GetEmuThread();
106 106
107 void keyPressEvent(QKeyEvent* event); 107 void keyPressEvent(QKeyEvent* event) override;
108 void keyReleaseEvent(QKeyEvent* event); 108 void keyReleaseEvent(QKeyEvent* event) override;
109
110 void ReloadSetKeymaps() override;
109 111
110public slots: 112public slots:
111 void moveContext(); 113 void moveContext();
@@ -116,4 +118,7 @@ private:
116 EmuThread emu_thread; 118 EmuThread emu_thread;
117 119
118 QByteArray geometry; 120 QByteArray geometry;
121
122 /// Device id of keyboard for use with KeyMap
123 int keyboard_id;
119}; 124};
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <QString>
6#include <QStringList>
7
8#include "core/settings.h"
9#include "core/core.h"
10#include "common/file_util.h"
11
12#include "config.h"
13
14Config::Config() {
15
16 // TODO: Don't hardcode the path; let the frontend decide where to put the config files.
17 qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini";
18 FileUtil::CreateFullPath(qt_config_loc);
19 qt_config = new QSettings(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
20
21 Reload();
22}
23
24void Config::ReadControls() {
25 qt_config->beginGroup("Controls");
26 Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt();
27 Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt();
28 Settings::values.pad_x_key = qt_config->value("pad_x", Qt::Key_Z).toInt();
29 Settings::values.pad_y_key = qt_config->value("pad_y", Qt::Key_X).toInt();
30 Settings::values.pad_l_key = qt_config->value("pad_l", Qt::Key_Q).toInt();
31 Settings::values.pad_r_key = qt_config->value("pad_r", Qt::Key_W).toInt();
32 Settings::values.pad_start_key = qt_config->value("pad_start", Qt::Key_M).toInt();
33 Settings::values.pad_select_key = qt_config->value("pad_select", Qt::Key_N).toInt();
34 Settings::values.pad_home_key = qt_config->value("pad_home", Qt::Key_B).toInt();
35 Settings::values.pad_dup_key = qt_config->value("pad_dup", Qt::Key_T).toInt();
36 Settings::values.pad_ddown_key = qt_config->value("pad_ddown", Qt::Key_G).toInt();
37 Settings::values.pad_dleft_key = qt_config->value("pad_dleft", Qt::Key_F).toInt();
38 Settings::values.pad_dright_key = qt_config->value("pad_dright", Qt::Key_H).toInt();
39 Settings::values.pad_sup_key = qt_config->value("pad_sup", Qt::Key_Up).toInt();
40 Settings::values.pad_sdown_key = qt_config->value("pad_sdown", Qt::Key_Down).toInt();
41 Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt();
42 Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt();
43 qt_config->endGroup();
44}
45
46void Config::SaveControls() {
47 qt_config->beginGroup("Controls");
48 qt_config->setValue("pad_a", Settings::values.pad_a_key);
49 qt_config->setValue("pad_b", Settings::values.pad_b_key);
50 qt_config->setValue("pad_x", Settings::values.pad_x_key);
51 qt_config->setValue("pad_y", Settings::values.pad_y_key);
52 qt_config->setValue("pad_l", Settings::values.pad_l_key);
53 qt_config->setValue("pad_r", Settings::values.pad_r_key);
54 qt_config->setValue("pad_start", Settings::values.pad_start_key);
55 qt_config->setValue("pad_select", Settings::values.pad_select_key);
56 qt_config->setValue("pad_home", Settings::values.pad_home_key);
57 qt_config->setValue("pad_dup", Settings::values.pad_dup_key);
58 qt_config->setValue("pad_ddown", Settings::values.pad_ddown_key);
59 qt_config->setValue("pad_dleft", Settings::values.pad_dleft_key);
60 qt_config->setValue("pad_dright", Settings::values.pad_dright_key);
61 qt_config->setValue("pad_sup", Settings::values.pad_sup_key);
62 qt_config->setValue("pad_sdown", Settings::values.pad_sdown_key);
63 qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key);
64 qt_config->setValue("pad_sright", Settings::values.pad_sright_key);
65 qt_config->endGroup();
66}
67
68void Config::ReadCore() {
69 qt_config->beginGroup("Core");
70 Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt();
71 Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 60).toInt();
72 qt_config->endGroup();
73}
74
75void Config::SaveCore() {
76 qt_config->beginGroup("Core");
77 qt_config->setValue("cpu_core", Settings::values.cpu_core);
78 qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate);
79 qt_config->endGroup();
80}
81
82void Config::ReadData() {
83 qt_config->beginGroup("Data Storage");
84 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
85 qt_config->endGroup();
86}
87
88void Config::SaveData() {
89 qt_config->beginGroup("Data Storage");
90 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
91 qt_config->endGroup();
92}
93
94void Config::Reload() {
95 ReadControls();
96 ReadCore();
97 ReadData();
98}
99
100void Config::Save() {
101 SaveControls();
102 SaveCore();
103 SaveData();
104}
105
106Config::~Config() {
107 Save();
108
109 delete qt_config;
110}
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QSettings>
8
9#include "common/common_types.h"
10
11class Config {
12 QSettings* qt_config;
13 std::string qt_config_loc;
14
15 void ReadControls();
16 void SaveControls();
17 void ReadCore();
18 void SaveCore();
19 void ReadData();
20 void SaveData();
21public:
22 Config();
23 ~Config();
24
25 void Reload();
26 void Save();
27};
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 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "common/break_points.h" 10#include "common/break_points.h"
11#include "common/symbols.h" 11#include "common/symbols.h"
12#include "core/arm/interpreter/armdefs.h" 12#include "core/arm/skyeye_common/armdefs.h"
13#include "core/arm/disassembler/arm_disasm.h" 13#include "core/arm/disassembler/arm_disasm.h"
14 14
15DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractItemModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { 15DisassemblerModel::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
17public: 17public:
18 GPUCommandListModel(QObject* parent); 18 GPUCommandListModel(QObject* parent);
19 19
20 int columnCount(const QModelIndex& parent = QModelIndex()) const; 20 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
21 int rowCount(const QModelIndex& parent = QModelIndex()) const override; 21 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
22 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; 22 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
23 23
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 @@
26#include "core/core.h" 26#include "core/core.h"
27#include "core/loader/loader.h" 27#include "core/loader/loader.h"
28#include "core/arm/disassembler/load_symbol_map.h" 28#include "core/arm/disassembler/load_symbol_map.h"
29#include "citra_qt/config.h"
29 30
30#include "version.h" 31#include "version.h"
31 32
32 33
33GMainWindow::GMainWindow() 34GMainWindow::GMainWindow()
34{ 35{
36 LogManager::Init();
37 Config config;
38
35 ui.setupUi(this); 39 ui.setupUi(this);
36 statusBar()->hide(); 40 statusBar()->hide();
37 41
@@ -112,8 +116,10 @@ GMainWindow::GMainWindow()
112 116
113 show(); 117 show();
114 118
115 LogManager::Init(); 119 QStringList args = QApplication::arguments();
116 System::Init(render_window); 120 if (args.length() >= 2) {
121 BootGame(args[1].toStdString());
122 }
117} 123}
118 124
119GMainWindow::~GMainWindow() 125GMainWindow::~GMainWindow()
@@ -125,10 +131,11 @@ GMainWindow::~GMainWindow()
125 131
126void GMainWindow::BootGame(std::string filename) 132void GMainWindow::BootGame(std::string filename)
127{ 133{
128 NOTICE_LOG(MASTER_LOG, "citra starting...\n"); 134 NOTICE_LOG(MASTER_LOG, "Citra starting...\n");
135 System::Init(render_window);
129 136
130 if (Core::Init()) { 137 if (Core::Init()) {
131 ERROR_LOG(MASTER_LOG, "core initialization failed, exiting..."); 138 ERROR_LOG(MASTER_LOG, "Core initialization failed, exiting...");
132 Core::Stop(); 139 Core::Stop();
133 exit(1); 140 exit(1);
134 } 141 }
@@ -146,6 +153,7 @@ void GMainWindow::BootGame(std::string filename)
146 render_window->GetEmuThread().start(); 153 render_window->GetEmuThread().start();
147 154
148 render_window->show(); 155 render_window->show();
156 OnStartGame();
149} 157}
150 158
151void GMainWindow::OnMenuLoadFile() 159void GMainWindow::OnMenuLoadFile()
@@ -182,6 +190,7 @@ void GMainWindow::OnPauseGame()
182void GMainWindow::OnStopGame() 190void GMainWindow::OnStopGame()
183{ 191{
184 render_window->GetEmuThread().SetCpuRunning(false); 192 render_window->GetEmuThread().SetCpuRunning(false);
193 // TODO: Shutdown core
185 194
186 ui.action_Start->setEnabled(true); 195 ui.action_Start->setEnabled(true);
187 ui.action_Pause->setEnabled(false); 196 ui.action_Pause->setEnabled(false);
@@ -243,7 +252,6 @@ int __cdecl main(int argc, char* argv[])
243 QApplication::setAttribute(Qt::AA_X11InitThreads); 252 QApplication::setAttribute(Qt::AA_X11InitThreads);
244 QApplication app(argc, argv); 253 QApplication app(argc, argv);
245 GMainWindow main_window; 254 GMainWindow main_window;
246
247 main_window.show(); 255 main_window.show();
248 return app.exec(); 256 return app.exec();
249} 257}
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:
32private: 32private:
33 void BootGame(std::string filename); 33 void BootGame(std::string filename);
34 34
35 void closeEvent(QCloseEvent* event); 35 void closeEvent(QCloseEvent* event) override;
36 36
37private slots: 37private slots:
38 void OnStartGame(); 38 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
4set(SRCS 4set(SRCS
5 break_points.cpp 5 break_points.cpp
6 console_listener.cpp 6 console_listener.cpp
7 emu_window.cpp
7 extended_trace.cpp 8 extended_trace.cpp
8 file_search.cpp 9 file_search.cpp
9 file_util.cpp 10 file_util.cpp
10 hash.cpp 11 hash.cpp
12 key_map.cpp
11 log_manager.cpp 13 log_manager.cpp
12 math_util.cpp 14 math_util.cpp
13 mem_arena.cpp 15 mem_arena.cpp
@@ -38,8 +40,8 @@ set(HEADERS
38 fifo_queue.h 40 fifo_queue.h
39 file_search.h 41 file_search.h
40 file_util.h 42 file_util.h
41 fixed_size_queue.h
42 hash.h 43 hash.h
44 key_map.h
43 linear_disk_cache.h 45 linear_disk_cache.h
44 log.h 46 log.h
45 log_manager.h 47 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 @@
68 * u32 hex; 68 * u32 hex;
69 * 69 *
70 * BitField<0,7,u32> first_seven_bits; // unsigned 70 * BitField<0,7,u32> first_seven_bits; // unsigned
71 * BitField<7,8,32> next_eight_bits; // unsigned 71 * BitField<7,8,u32> next_eight_bits; // unsigned
72 * BitField<3,15,s32> some_signed_fields; // signed 72 * BitField<3,15,s32> some_signed_fields; // signed
73 * }; 73 * };
74 * 74 *
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 @@
32#include <string> 32#include <string>
33#include <list> 33#include <list>
34#include <set> 34#include <set>
35#ifndef __SYMBIAN32__
36#if defined(IOS) || defined(MACGNUSTD)
37#include <tr1/type_traits>
38#else
39#include <type_traits> 35#include <type_traits>
40#endif
41#endif
42 36
43#include "common/common.h" 37#include "common/common.h"
44#include "common/file_util.h" 38#include "common/file_util.h"
45//#include "../ext/snappy/snappy-c.h"
46
47#if defined(IOS) || defined(MACGNUSTD)
48namespace std {
49 using tr1::is_pointer;
50}
51#endif
52#ifdef __SYMBIAN32__
53namespace std {
54 template <bool bool_value>
55 struct bool_constant {
56 typedef bool_constant<bool_value> type;
57 static const bool value = bool_value;
58 };
59 template <bool bool_value> const bool bool_constant<bool_value>::value;
60 template <typename T> struct is_pointer : public bool_constant<false> {};
61 template <typename T> struct is_pointer<T*> : public bool_constant<true> {};
62}
63#endif
64 39
65template <class T> 40template <class T>
66struct LinkedListItem : public T 41struct LinkedListItem : public T
@@ -651,222 +626,3 @@ inline PointerWrapSection::~PointerWrapSection() {
651 p_.DoMarker(title_); 626 p_.DoMarker(title_);
652 } 627 }
653} 628}
654
655
656// Commented out because it is currently unused, and breaks builds on OSX
657/*class CChunkFileReader
658{
659public:
660 enum Error {
661 ERROR_NONE,
662 ERROR_BAD_FILE,
663 ERROR_BROKEN_STATE,
664 };
665
666 // Load file template
667 template<class T>
668 static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason)
669 {
670 INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str());
671 _failureReason->clear();
672 _failureReason->append("LoadStateWrongVersion");
673
674 if (!File::Exists(_rFilename)) {
675 _failureReason->clear();
676 _failureReason->append("LoadStateDoesntExist");
677 ERROR_LOG(COMMON, "ChunkReader: File doesn't exist");
678 return ERROR_BAD_FILE;
679 }
680
681 // Check file size
682 const u64 fileSize = File::GetSize(_rFilename);
683 static const u64 headerSize = sizeof(SChunkHeader);
684 if (fileSize < headerSize)
685 {
686 ERROR_LOG(COMMON,"ChunkReader: File too small");
687 return ERROR_BAD_FILE;
688 }
689
690 File::IOFile pFile(_rFilename, "rb");
691 if (!pFile)
692 {
693 ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading");
694 return ERROR_BAD_FILE;
695 }
696
697 // read the header
698 SChunkHeader header;
699 if (!pFile.ReadArray(&header, 1))
700 {
701 ERROR_LOG(COMMON,"ChunkReader: Bad header size");
702 return ERROR_BAD_FILE;
703 }
704
705 // Check revision
706 if (header.Revision != _Revision)
707 {
708 ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d",
709 header.Revision, _Revision);
710 return ERROR_BAD_FILE;
711 }
712
713 if (strcmp(header.GitVersion, _VersionString) != 0)
714 {
715 WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.",
716 header.GitVersion);
717 }
718
719 // get size
720 const int sz = (int)(fileSize - headerSize);
721 if (header.ExpectedSize != sz)
722 {
723 ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d",
724 sz, header.ExpectedSize);
725 return ERROR_BAD_FILE;
726 }
727
728 // read the state
729 u8* buffer = new u8[sz];
730 if (!pFile.ReadBytes(buffer, sz))
731 {
732 ERROR_LOG(COMMON,"ChunkReader: Error reading file");
733 return ERROR_BAD_FILE;
734 }
735
736 u8 *ptr = buffer;
737 u8 *buf = buffer;
738 if (header.Compress) {
739 u8 *uncomp_buffer = new u8[header.UncompressedSize];
740 size_t uncomp_size = header.UncompressedSize;
741 snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size);
742 if ((int)uncomp_size != header.UncompressedSize) {
743 ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size);
744 }
745 ptr = uncomp_buffer;
746 buf = uncomp_buffer;
747 delete [] buffer;
748 }
749
750 PointerWrap p(&ptr, PointerWrap::MODE_READ);
751 _class.DoState(p);
752 delete[] buf;
753
754 INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str());
755 if (p.error != p.ERROR_FAILURE) {
756 return ERROR_NONE;
757 } else {
758 return ERROR_BROKEN_STATE;
759 }
760 }
761
762 // Save file template
763 template<class T>
764 static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class)
765 {
766 INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str());
767
768 File::IOFile pFile(_rFilename, "wb");
769 if (!pFile)
770 {
771 ERROR_LOG(COMMON,"ChunkReader: Error opening file for write");
772 return ERROR_BAD_FILE;
773 }
774
775 bool compress = true;
776
777 // Get data
778 u8 *ptr = 0;
779 PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
780 _class.DoState(p);
781 size_t const sz = (size_t)ptr;
782
783 u8 * buffer = new u8[sz];
784 ptr = &buffer[0];
785 p.SetMode(PointerWrap::MODE_WRITE);
786 _class.DoState(p);
787
788 // Create header
789 SChunkHeader header;
790 header.Compress = compress ? 1 : 0;
791 header.Revision = _Revision;
792 header.ExpectedSize = (int)sz;
793 header.UncompressedSize = (int)sz;
794 strncpy(header.GitVersion, _VersionString, 32);
795 header.GitVersion[31] = '\0';
796
797 // Write to file
798 if (compress) {
799 size_t comp_len = snappy_max_compressed_length(sz);
800 u8 *compressed_buffer = new u8[comp_len];
801 snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len);
802 delete [] buffer;
803 header.ExpectedSize = (int)comp_len;
804 if (!pFile.WriteArray(&header, 1))
805 {
806 ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
807 return ERROR_BAD_FILE;
808 }
809 if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) {
810 ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data");
811 return ERROR_BAD_FILE;
812 } else {
813 INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len);
814 }
815 delete [] compressed_buffer;
816 } else {
817 if (!pFile.WriteArray(&header, 1))
818 {
819 ERROR_LOG(COMMON,"ChunkReader: Failed writing header");
820 return ERROR_BAD_FILE;
821 }
822 if (!pFile.WriteBytes(&buffer[0], sz))
823 {
824 ERROR_LOG(COMMON,"ChunkReader: Failed writing data");
825 return ERROR_BAD_FILE;
826 }
827 delete [] buffer;
828 }
829
830 INFO_LOG(COMMON,"ChunkReader: Done writing %s",
831 _rFilename.c_str());
832 if (p.error != p.ERROR_FAILURE) {
833 return ERROR_NONE;
834 } else {
835 return ERROR_BROKEN_STATE;
836 }
837 }
838
839 template <class T>
840 static Error Verify(T& _class)
841 {
842 u8 *ptr = 0;
843
844 // Step 1: Measure the space required.
845 PointerWrap p(&ptr, PointerWrap::MODE_MEASURE);
846 _class.DoState(p);
847 size_t const sz = (size_t)ptr;
848 std::vector<u8> buffer(sz);
849
850 // Step 2: Dump the state.
851 ptr = &buffer[0];
852 p.SetMode(PointerWrap::MODE_WRITE);
853 _class.DoState(p);
854
855 // Step 3: Verify the state.
856 ptr = &buffer[0];
857 p.SetMode(PointerWrap::MODE_VERIFY);
858 _class.DoState(p);
859
860 return ERROR_NONE;
861 }
862
863private:
864 struct SChunkHeader
865 {
866 int Revision;
867 int Compress;
868 int ExpectedSize;
869 int UncompressedSize;
870 char GitVersion[32];
871 };
872}; */
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 @@
20 20
21#define STACKALIGN 21#define STACKALIGN
22 22
23#if __cplusplus >= 201103L || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__)
24#define HAVE_CXX11_SYNTAX 1
25#endif
26
27#if HAVE_CXX11_SYNTAX
28// An inheritable class to disallow the copy constructor and operator= functions 23// An inheritable class to disallow the copy constructor and operator= functions
29class NonCopyable 24class NonCopyable
30{ 25{
@@ -36,7 +31,6 @@ private:
36 NonCopyable(NonCopyable&); 31 NonCopyable(NonCopyable&);
37 NonCopyable& operator=(NonCopyable& other); 32 NonCopyable& operator=(NonCopyable& other);
38}; 33};
39#endif
40 34
41#include "common/log.h" 35#include "common/log.h"
42#include "common/common_types.h" 36#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 @@
7// Make sure we pick up USER_DIR if set in config.h 7// Make sure we pick up USER_DIR if set in config.h
8#include "common/common.h" 8#include "common/common.h"
9 9
10// Directory seperators, do we need this? 10// Directory separators, do we need this?
11#define DIR_SEP "/" 11#define DIR_SEP "/"
12#define DIR_SEP_CHR '/' 12#define DIR_SEP_CHR '/'
13 13
14#ifndef MAX_PATH 14#ifndef MAX_PATH
15#define MAX_PATH 260 15#define MAX_PATH 260
16#endif 16#endif
17 17
18// The user data dir 18// The user data dir
19#define ROOT_DIR "." 19#define ROOT_DIR "."
20#ifdef _WIN32 20#ifdef _WIN32
21 #define USERDATA_DIR "user" 21 #define USERDATA_DIR "user"
22 #define EMU_DATA_DIR "emu" 22 #define EMU_DATA_DIR "Citra Emulator"
23#else 23#else
24 #define USERDATA_DIR "user" 24 #define USERDATA_DIR "user"
25 #ifdef USER_DIR 25 #ifdef USER_DIR
26 #define EMU_DATA_DIR USER_DIR 26 #define EMU_DATA_DIR USER_DIR
27 #else 27 #else
28 #define EMU_DATA_DIR ".emu" 28 #define EMU_DATA_DIR ".citra-emu"
29 #endif 29 #endif
30#endif 30#endif
31 31
@@ -48,29 +48,30 @@
48#define JAP_DIR "JAP" 48#define JAP_DIR "JAP"
49 49
50// Subdirs in the User dir returned by GetUserPath(D_USER_IDX) 50// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
51#define CONFIG_DIR "config" 51#define CONFIG_DIR "config"
52#define GAMECONFIG_DIR "game_config" 52#define GAMECONFIG_DIR "game_config"
53#define MAPS_DIR "maps" 53#define MAPS_DIR "maps"
54#define CACHE_DIR "cache" 54#define CACHE_DIR "cache"
55#define SHADERCACHE_DIR "shader_cache" 55#define SDMC_DIR "sdmc"
56#define STATESAVES_DIR "state_saves" 56#define SHADERCACHE_DIR "shader_cache"
57#define SCREENSHOTS_DIR "screenShots" 57#define STATESAVES_DIR "state_saves"
58#define DUMP_DIR "dump" 58#define SCREENSHOTS_DIR "screenShots"
59#define DUMP_TEXTURES_DIR "textures" 59#define DUMP_DIR "dump"
60#define DUMP_FRAMES_DIR "frames" 60#define DUMP_TEXTURES_DIR "textures"
61#define DUMP_AUDIO_DIR "audio" 61#define DUMP_FRAMES_DIR "frames"
62#define LOGS_DIR "logs" 62#define DUMP_AUDIO_DIR "audio"
63#define SHADERS_DIR "shaders" 63#define LOGS_DIR "logs"
64#define SYSCONF_DIR "sysconf" 64#define SHADERS_DIR "shaders"
65#define SYSCONF_DIR "sysconf"
65 66
66// Filenames 67// Filenames
67// Files in the directory returned by GetUserPath(D_CONFIG_IDX) 68// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
68#define EMU_CONFIG "emu.ini" 69#define EMU_CONFIG "emu.ini"
69#define DEBUGGER_CONFIG "debugger.ini" 70#define DEBUGGER_CONFIG "debugger.ini"
70#define LOGGER_CONFIG "logger.ini" 71#define LOGGER_CONFIG "logger.ini"
71 72
72// Files in the directory returned by GetUserPath(D_LOGS_IDX) 73// Files in the directory returned by GetUserPath(D_LOGS_IDX)
73#define MAIN_LOG "emu.log" 74#define MAIN_LOG "emu.log"
74 75
75// Files in the directory returned by GetUserPath(D_SYSCONF_IDX) 76// Files in the directory returned by GetUserPath(D_SYSCONF_IDX)
76#define SYSCONF "SYSCONF" 77#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 @@
25#pragma once 25#pragma once
26 26
27#include <cmath> 27#include <cmath>
28#include <cstdint>
28#include <xmmintrin.h> // data_types__m128.cpp 29#include <xmmintrin.h> // data_types__m128.cpp
29 30
30#ifdef _WIN32 31typedef std::uint8_t u8; ///< 8-bit unsigned byte
32typedef std::uint16_t u16; ///< 16-bit unsigned short
33typedef std::uint32_t u32; ///< 32-bit unsigned word
34typedef std::uint64_t u64; ///< 64-bit unsigned int
31 35
32#include <tchar.h> 36typedef std::int8_t s8; ///< 8-bit signed byte
37typedef std::int16_t s16; ///< 16-bit signed short
38typedef std::int32_t s32; ///< 32-bit signed word
39typedef std::int64_t s64; ///< 64-bit signed int
33 40
34typedef unsigned __int8 u8; ///< 8-bit unsigned byte 41typedef float f32; ///< 32-bit floating point
35typedef unsigned __int16 u16; ///< 16-bit unsigned short 42typedef double f64; ///< 64-bit floating point
36typedef unsigned __int32 u32; ///< 32-bit unsigned word
37typedef unsigned __int64 u64; ///< 64-bit unsigned int
38
39typedef signed __int8 s8; ///< 8-bit signed byte
40typedef signed __int16 s16; ///< 16-bit signed short
41typedef signed __int32 s32; ///< 32-bit signed word
42typedef signed __int64 s64; ///< 64-bit signed int
43
44#else
45
46typedef unsigned char u8; ///< 8-bit unsigned byte
47typedef unsigned short u16; ///< 16-bit unsigned short
48typedef unsigned int u32; ///< 32-bit unsigned word
49typedef unsigned long long u64; ///< 64-bit unsigned int
50
51typedef signed char s8; ///< 8-bit signed byte
52typedef signed short s16; ///< 16-bit signed short
53typedef signed int s32; ///< 32-bit signed word
54typedef signed long long s64; ///< 64-bit signed int
55
56// For using windows lock code
57#define TCHAR char
58#define LONG int
59
60#endif // _WIN32
61
62typedef float f32; ///< 32-bit floating point
63typedef double f64; ///< 64-bit floating point
64 43
65#include "common/common.h" 44#include "common/common.h"
66 45
@@ -100,7 +79,7 @@ union t128 {
100 __m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers) 79 __m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers)
101}; 80};
102 81
103namespace common { 82namespace Common {
104/// Rectangle data structure 83/// Rectangle data structure
105class Rect { 84class Rect {
106public: 85public:
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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cmath> 6
7#include <cstdio>
8#include <string>
9#ifdef _WIN32 7#ifdef _WIN32
10#include <windows.h> 8#include <windows.h>
11#include <array> 9#include <array>
12#else
13#include <cstdarg>
14#endif 10#endif
15 11
16#include "common/common.h" 12#include "common/common.h"
@@ -47,7 +43,7 @@ void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title
47 // Save the window handle that AllocConsole() created 43 // Save the window handle that AllocConsole() created
48 hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 44 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
49 // Set the console window title 45 // Set the console window title
50 SetConsoleTitle(UTF8ToTStr(Title).c_str()); 46 SetConsoleTitle(Common::UTF8ToTStr(Title).c_str());
51 // Set letter space 47 // Set letter space
52 LetterSpace(80, 4000); 48 LetterSpace(80, 4000);
53 //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); 49 //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
@@ -193,11 +189,11 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
193 { 189 {
194 Str.resize(Str.size() + 1); 190 Str.resize(Str.size() + 1);
195 if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) 191 if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead))
196 SLog += StringFromFormat("WriteConsoleOutputCharacter error"); 192 SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error");
197 193
198 Attr.resize(Attr.size() + 1); 194 Attr.resize(Attr.size() + 1);
199 if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) 195 if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead))
200 SLog += StringFromFormat("WriteConsoleOutputAttribute error"); 196 SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error");
201 197
202 // Break on error 198 // Break on error
203 if (cAttrRead == 0) break; 199 if (cAttrRead == 0) break;
@@ -223,9 +219,9 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
223 for (size_t i = 0; i < Attr.size(); i++) 219 for (size_t i = 0; i < Attr.size(); i++)
224 { 220 {
225 if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) 221 if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten))
226 SLog += StringFromFormat("WriteConsoleOutputCharacter error"); 222 SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error");
227 if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) 223 if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten))
228 SLog += StringFromFormat("WriteConsoleOutputAttribute error"); 224 SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error");
229 225
230 BytesWritten += cAttrWritten; 226 BytesWritten += cAttrWritten;
231 coordScreen = GetCoordinates(BytesWritten, LBufWidth); 227 coordScreen = GetCoordinates(BytesWritten, LBufWidth);
@@ -245,16 +241,6 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
245void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) 241void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
246{ 242{
247#if defined(_WIN32) 243#if defined(_WIN32)
248 /*
249 const int MAX_BYTES = 1024*10;
250 char Str[MAX_BYTES];
251 va_list ArgPtr;
252 int Cnt;
253 va_start(ArgPtr, Text);
254 Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr);
255 va_end(ArgPtr);
256 */
257 DWORD cCharsWritten;
258 WORD Color; 244 WORD Color;
259 245
260 switch (Level) 246 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:
26#ifdef _WIN32 26#ifdef _WIN32
27 COORD GetCoordinates(int BytesRead, int BufferWidth); 27 COORD GetCoordinates(int BytesRead, int BufferWidth);
28#endif 28#endif
29 void Log(LogTypes::LOG_LEVELS, const char *Text); 29 void Log(LogTypes::LOG_LEVELS, const char *Text) override;
30 void ClearScreen(bool Cursor = true); 30 void ClearScreen(bool Cursor = true);
31 31
32private: 32private:
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "emu_window.h"
6
7void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) {
8 HID_User::PadState mapped_key = KeyMap::GetPadKey(key);
9
10 HID_User::PadButtonPress(mapped_key);
11}
12
13void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) {
14 HID_User::PadState mapped_key = KeyMap::GetPadKey(key);
15
16 HID_User::PadButtonRelease(mapped_key);
17}
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 @@
6 6
7#include "common/common.h" 7#include "common/common.h"
8#include "common/scm_rev.h" 8#include "common/scm_rev.h"
9#include "common/string_util.h"
10#include "common/key_map.h"
9 11
10// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, 12// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL,
11// QGLWidget, GLFW, etc...) 13// QGLWidget, GLFW, etc...)
@@ -14,7 +16,7 @@ class EmuWindow
14 16
15public: 17public:
16 /// Data structure to store an emuwindow configuration 18 /// Data structure to store an emuwindow configuration
17 struct Config{ 19 struct WindowConfig {
18 bool fullscreen; 20 bool fullscreen;
19 int res_width; 21 int res_width;
20 int res_height; 22 int res_height;
@@ -32,11 +34,19 @@ public:
32 /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread 34 /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
33 virtual void DoneCurrent() = 0; 35 virtual void DoneCurrent() = 0;
34 36
35 Config GetConfig() const { 37 virtual void ReloadSetKeymaps() = 0;
38
39 /// Signals a key press action to the HID module
40 static void KeyPressed(KeyMap::HostDeviceKey key);
41
42 /// Signals a key release action to the HID module
43 static void KeyReleased(KeyMap::HostDeviceKey key);
44
45 WindowConfig GetConfig() const {
36 return m_config; 46 return m_config;
37 } 47 }
38 48
39 void SetConfig(const Config& val) { 49 void SetConfig(const WindowConfig& val) {
40 m_config = val; 50 m_config = val;
41 } 51 }
42 52
@@ -65,11 +75,11 @@ public:
65 } 75 }
66 76
67protected: 77protected:
68 EmuWindow() : m_client_area_width(640), m_client_area_height(480) { 78 EmuWindow():
69 char window_title[255]; 79 m_client_area_width(640),
70 sprintf(window_title, "Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); 80 m_client_area_height(480),
71 m_window_title = window_title; 81 m_window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc))
72 } 82 {}
73 virtual ~EmuWindow() {} 83 virtual ~EmuWindow() {}
74 84
75 std::string m_window_title; ///< Current window title, should be used by window impl. 85 std::string m_window_title; ///< Current window title, should be used by window impl.
@@ -78,6 +88,6 @@ protected:
78 int m_client_area_height; ///< Current client height, should be set by window impl. 88 int m_client_area_height; ///< Current client height, should be set by window impl.
79 89
80private: 90private:
81 Config m_config; ///< Internal configuration 91 WindowConfig m_config; ///< Internal configuration
82 92
83}; 93};
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)
278 278
279 GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); 279 GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo);
280 GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); 280 GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo);
281 etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n"); 281 etfprint(file, " " + Common::TStrToUTF8(srcInfo) + " : " + Common::TStrToUTF8(symInfo) + "\n");
282} 282}
283 283
284void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) 284void 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 @@
4 4
5 5
6#include "common/common.h" 6#include "common/common.h"
7#include "common/common_paths.h" 7
8#ifndef _WIN32 8#ifndef _WIN32
9#include <sys/types.h>
10#include <dirent.h> 9#include <dirent.h>
11#else 10#else
12#include <windows.h> 11#include <windows.h>
13#endif 12#endif
14 13
15#include <string>
16#include <algorithm> 14#include <algorithm>
17 15
18#include "common/file_search.h" 16#include "common/file_search.h"
@@ -35,10 +33,10 @@ CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, cons
35void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) 33void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath)
36{ 34{
37 std::string GCMSearchPath; 35 std::string GCMSearchPath;
38 BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); 36 Common::BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
39#ifdef _WIN32 37#ifdef _WIN32
40 WIN32_FIND_DATA findData; 38 WIN32_FIND_DATA findData;
41 HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); 39 HANDLE FindFirst = FindFirstFile(Common::UTF8ToTStr(GCMSearchPath).c_str(), &findData);
42 40
43 if (FindFirst != INVALID_HANDLE_VALUE) 41 if (FindFirst != INVALID_HANDLE_VALUE)
44 { 42 {
@@ -49,7 +47,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
49 if (findData.cFileName[0] != '.') 47 if (findData.cFileName[0] != '.')
50 { 48 {
51 std::string strFilename; 49 std::string strFilename;
52 BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); 50 Common::BuildCompleteFilename(strFilename, _strPath, Common::TStrToUTF8(findData.cFileName));
53 m_FileNames.push_back(strFilename); 51 m_FileNames.push_back(strFilename);
54 } 52 }
55 53
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 @@
4 4
5 5
6#include "common/common.h" 6#include "common/common.h"
7#include "common/common_paths.h"
8#include "common/file_util.h" 7#include "common/file_util.h"
9#include "common/string_util.h"
10 8
11#ifdef _WIN32 9#ifdef _WIN32
12#include <windows.h> 10#include <windows.h>
@@ -15,11 +13,9 @@
15#include <commdlg.h> // for GetSaveFileName 13#include <commdlg.h> // for GetSaveFileName
16#include <io.h> 14#include <io.h>
17#include <direct.h> // getcwd 15#include <direct.h> // getcwd
16#include <tchar.h>
18#else 17#else
19#include <cerrno>
20#include <cstdlib>
21#include <sys/param.h> 18#include <sys/param.h>
22#include <sys/types.h>
23#include <dirent.h> 19#include <dirent.h>
24#endif 20#endif
25 21
@@ -32,8 +28,6 @@
32#include <algorithm> 28#include <algorithm>
33#include <sys/stat.h> 29#include <sys/stat.h>
34 30
35#include "common/string_util.h"
36
37#ifndef S_ISDIR 31#ifndef S_ISDIR
38#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) 32#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
39#endif 33#endif
@@ -46,7 +40,7 @@
46// This namespace has various generic functions related to files and paths. 40// This namespace has various generic functions related to files and paths.
47// The code still needs a ton of cleanup. 41// The code still needs a ton of cleanup.
48// REMEMBER: strdup considered harmful! 42// REMEMBER: strdup considered harmful!
49namespace File 43namespace FileUtil
50{ 44{
51 45
52// Remove any ending forward slashes from directory paths 46// Remove any ending forward slashes from directory paths
@@ -71,7 +65,7 @@ bool Exists(const std::string &filename)
71 StripTailDirSlashes(copy); 65 StripTailDirSlashes(copy);
72 66
73#ifdef _WIN32 67#ifdef _WIN32
74 int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); 68 int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info);
75#else 69#else
76 int result = stat64(copy.c_str(), &file_info); 70 int result = stat64(copy.c_str(), &file_info);
77#endif 71#endif
@@ -88,7 +82,7 @@ bool IsDirectory(const std::string &filename)
88 StripTailDirSlashes(copy); 82 StripTailDirSlashes(copy);
89 83
90#ifdef _WIN32 84#ifdef _WIN32
91 int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); 85 int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info);
92#else 86#else
93 int result = stat64(copy.c_str(), &file_info); 87 int result = stat64(copy.c_str(), &file_info);
94#endif 88#endif
@@ -124,7 +118,7 @@ bool Delete(const std::string &filename)
124 } 118 }
125 119
126#ifdef _WIN32 120#ifdef _WIN32
127 if (!DeleteFile(UTF8ToTStr(filename).c_str())) 121 if (!DeleteFile(Common::UTF8ToTStr(filename).c_str()))
128 { 122 {
129 WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", 123 WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s",
130 filename.c_str(), GetLastErrorMsg()); 124 filename.c_str(), GetLastErrorMsg());
@@ -146,7 +140,7 @@ bool CreateDir(const std::string &path)
146{ 140{
147 INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); 141 INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
148#ifdef _WIN32 142#ifdef _WIN32
149 if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) 143 if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), NULL))
150 return true; 144 return true;
151 DWORD error = GetLastError(); 145 DWORD error = GetLastError();
152 if (error == ERROR_ALREADY_EXISTS) 146 if (error == ERROR_ALREADY_EXISTS)
@@ -179,7 +173,7 @@ bool CreateFullPath(const std::string &fullPath)
179 int panicCounter = 100; 173 int panicCounter = 100;
180 INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); 174 INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str());
181 175
182 if (File::Exists(fullPath)) 176 if (FileUtil::Exists(fullPath))
183 { 177 {
184 INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); 178 INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str());
185 return true; 179 return true;
@@ -197,8 +191,10 @@ bool CreateFullPath(const std::string &fullPath)
197 191
198 // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") 192 // Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
199 std::string const subPath(fullPath.substr(0, position + 1)); 193 std::string const subPath(fullPath.substr(0, position + 1));
200 if (!File::IsDirectory(subPath)) 194 if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
201 File::CreateDir(subPath); 195 ERROR_LOG(COMMON, "CreateFullPath: directory creation failed");
196 return false;
197 }
202 198
203 // A safety check 199 // A safety check
204 panicCounter--; 200 panicCounter--;
@@ -218,14 +214,14 @@ bool DeleteDir(const std::string &filename)
218 INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); 214 INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str());
219 215
220 // check if a directory 216 // check if a directory
221 if (!File::IsDirectory(filename)) 217 if (!FileUtil::IsDirectory(filename))
222 { 218 {
223 ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); 219 ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str());
224 return false; 220 return false;
225 } 221 }
226 222
227#ifdef _WIN32 223#ifdef _WIN32
228 if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) 224 if (::RemoveDirectory(Common::UTF8ToTStr(filename).c_str()))
229 return true; 225 return true;
230#else 226#else
231 if (rmdir(filename.c_str()) == 0) 227 if (rmdir(filename.c_str()) == 0)
@@ -254,7 +250,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
254 INFO_LOG(COMMON, "Copy: %s --> %s", 250 INFO_LOG(COMMON, "Copy: %s --> %s",
255 srcFilename.c_str(), destFilename.c_str()); 251 srcFilename.c_str(), destFilename.c_str());
256#ifdef _WIN32 252#ifdef _WIN32
257 if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) 253 if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE))
258 return true; 254 return true;
259 255
260 ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", 256 ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
@@ -342,7 +338,7 @@ u64 GetSize(const std::string &filename)
342 338
343 struct stat64 buf; 339 struct stat64 buf;
344#ifdef _WIN32 340#ifdef _WIN32
345 if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) 341 if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0)
346#else 342#else
347 if (stat64(filename.c_str(), &buf) == 0) 343 if (stat64(filename.c_str(), &buf) == 0)
348#endif 344#endif
@@ -393,7 +389,7 @@ bool CreateEmptyFile(const std::string &filename)
393{ 389{
394 INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); 390 INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
395 391
396 if (!File::IOFile(filename, "wb")) 392 if (!FileUtil::IOFile(filename, "wb"))
397 { 393 {
398 ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", 394 ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s",
399 filename.c_str(), GetLastErrorMsg()); 395 filename.c_str(), GetLastErrorMsg());
@@ -415,7 +411,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
415 // Find the first file in the directory. 411 // Find the first file in the directory.
416 WIN32_FIND_DATA ffd; 412 WIN32_FIND_DATA ffd;
417 413
418 HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); 414 HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd);
419 if (hFind == INVALID_HANDLE_VALUE) 415 if (hFind == INVALID_HANDLE_VALUE)
420 { 416 {
421 FindClose(hFind); 417 FindClose(hFind);
@@ -425,7 +421,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
425 do 421 do
426 { 422 {
427 FSTEntry entry; 423 FSTEntry entry;
428 const std::string virtualName(TStrToUTF8(ffd.cFileName)); 424 const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
429#else 425#else
430 struct dirent dirent, *result = NULL; 426 struct dirent dirent, *result = NULL;
431 427
@@ -482,7 +478,7 @@ bool DeleteDirRecursively(const std::string &directory)
482#ifdef _WIN32 478#ifdef _WIN32
483 // Find the first file in the directory. 479 // Find the first file in the directory.
484 WIN32_FIND_DATA ffd; 480 WIN32_FIND_DATA ffd;
485 HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); 481 HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd);
486 482
487 if (hFind == INVALID_HANDLE_VALUE) 483 if (hFind == INVALID_HANDLE_VALUE)
488 { 484 {
@@ -493,7 +489,7 @@ bool DeleteDirRecursively(const std::string &directory)
493 // windows loop 489 // windows loop
494 do 490 do
495 { 491 {
496 const std::string virtualName(TStrToUTF8(ffd.cFileName)); 492 const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
497#else 493#else
498 struct dirent dirent, *result = NULL; 494 struct dirent dirent, *result = NULL;
499 DIR *dirp = opendir(directory.c_str()); 495 DIR *dirp = opendir(directory.c_str());
@@ -526,7 +522,7 @@ bool DeleteDirRecursively(const std::string &directory)
526 } 522 }
527 else 523 else
528 { 524 {
529 if (!File::Delete(newPath)) 525 if (!FileUtil::Delete(newPath))
530 { 526 {
531 #ifndef _WIN32 527 #ifndef _WIN32
532 closedir(dirp); 528 closedir(dirp);
@@ -543,7 +539,7 @@ bool DeleteDirRecursively(const std::string &directory)
543 } 539 }
544 closedir(dirp); 540 closedir(dirp);
545#endif 541#endif
546 File::DeleteDir(directory); 542 FileUtil::DeleteDir(directory);
547 543
548 return true; 544 return true;
549} 545}
@@ -553,8 +549,8 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
553{ 549{
554#ifndef _WIN32 550#ifndef _WIN32
555 if (source_path == dest_path) return; 551 if (source_path == dest_path) return;
556 if (!File::Exists(source_path)) return; 552 if (!FileUtil::Exists(source_path)) return;
557 if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); 553 if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path);
558 554
559 struct dirent dirent, *result = NULL; 555 struct dirent dirent, *result = NULL;
560 DIR *dirp = opendir(source_path.c_str()); 556 DIR *dirp = opendir(source_path.c_str());
@@ -576,10 +572,10 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
576 { 572 {
577 source += '/'; 573 source += '/';
578 dest += '/'; 574 dest += '/';
579 if (!File::Exists(dest)) File::CreateFullPath(dest); 575 if (!FileUtil::Exists(dest)) FileUtil::CreateFullPath(dest);
580 CopyDir(source, dest); 576 CopyDir(source, dest);
581 } 577 }
582 else if (!File::Exists(dest)) File::Copy(source, dest); 578 else if (!FileUtil::Exists(dest)) FileUtil::Copy(source, dest);
583 } 579 }
584 closedir(dirp); 580 closedir(dirp);
585#endif 581#endif
@@ -631,7 +627,7 @@ std::string& GetExeDirectory()
631 { 627 {
632 TCHAR Dolphin_exe_Path[2048]; 628 TCHAR Dolphin_exe_Path[2048];
633 GetModuleFileName(NULL, Dolphin_exe_Path, 2048); 629 GetModuleFileName(NULL, Dolphin_exe_Path, 2048);
634 DolphinPath = TStrToUTF8(Dolphin_exe_Path); 630 DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path);
635 DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); 631 DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
636 } 632 }
637 return DolphinPath; 633 return DolphinPath;
@@ -655,7 +651,7 @@ std::string GetSysDirectory()
655 return sysDir; 651 return sysDir;
656} 652}
657 653
658// Returns a string with a Dolphin data dir or file in the user's home 654// Returns a string with a Citra data dir or file in the user's home
659// directory. To be used in "multi-user" mode (that is, installed). 655// directory. To be used in "multi-user" mode (that is, installed).
660const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) 656const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath)
661{ 657{
@@ -667,7 +663,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
667#ifdef _WIN32 663#ifdef _WIN32
668 paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; 664 paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
669#else 665#else
670 if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) 666 if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
671 paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; 667 paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
672 else 668 else
673 paths[D_USER_IDX] = std::string(getenv("HOME") ? 669 paths[D_USER_IDX] = std::string(getenv("HOME") ?
@@ -675,27 +671,28 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
675 getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP; 671 getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP;
676#endif 672#endif
677 673
678 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; 674 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
679 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; 675 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
680 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; 676 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
681 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 677 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
678 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
682 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; 679 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
683 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; 680 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
684 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; 681 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
685 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; 682 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
686 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; 683 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
687 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; 684 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
688 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; 685 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
689 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; 686 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
690 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; 687 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
691 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; 688 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
692 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; 689 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
693 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; 690 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
694 } 691 }
695 692
696 if (!newPath.empty()) 693 if (!newPath.empty())
697 { 694 {
698 if (!File::IsDirectory(newPath)) 695 if (!FileUtil::IsDirectory(newPath))
699 { 696 {
700 WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); 697 WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str());
701 return paths[DirIDX]; 698 return paths[DirIDX];
@@ -708,43 +705,44 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
708 switch (DirIDX) 705 switch (DirIDX)
709 { 706 {
710 case D_ROOT_IDX: 707 case D_ROOT_IDX:
711 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; 708 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
712 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; 709 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP;
713 paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; 710 paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF;
714 break; 711 break;
715 712
716 case D_USER_IDX: 713 case D_USER_IDX:
717 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; 714 paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
718 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; 715 paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
719 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; 716 paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
720 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; 717 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
721 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 718 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
719 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
722 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; 720 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
723 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; 721 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
724 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; 722 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
725 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; 723 paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
726 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; 724 paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
727 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; 725 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
728 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; 726 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
729 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; 727 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
730 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; 728 paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
731 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; 729 paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP;
732 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; 730 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
733 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; 731 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
734 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; 732 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
735 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; 733 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
736 break; 734 break;
737 735
738 case D_CONFIG_IDX: 736 case D_CONFIG_IDX:
739 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; 737 paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
740 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; 738 paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
741 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; 739 paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
742 break; 740 break;
743 741
744 case D_DUMP_IDX: 742 case D_DUMP_IDX:
745 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; 743 paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
746 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; 744 paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
747 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; 745 paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
748 break; 746 break;
749 747
750 case D_LOGS_IDX: 748 case D_LOGS_IDX:
@@ -757,25 +755,25 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
757 755
758//std::string GetThemeDir(const std::string& theme_name) 756//std::string GetThemeDir(const std::string& theme_name)
759//{ 757//{
760// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; 758// std::string dir = FileUtil::GetUserPath(D_THEMES_IDX) + theme_name + "/";
761// 759//
762//#if !defined(_WIN32) 760//#if !defined(_WIN32)
763// // If theme does not exist in user's dir load from shared directory 761// // If theme does not exist in user's dir load from shared directory
764// if (!File::Exists(dir)) 762// if (!FileUtil::Exists(dir))
765// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; 763// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
766//#endif 764//#endif
767// 765//
768// return dir; 766// return dir;
769//} 767//}
770 768
771bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) 769size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename)
772{ 770{
773 return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); 771 return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
774} 772}
775 773
776bool ReadFileToString(bool text_file, const char *filename, std::string &str) 774size_t ReadFileToString(bool text_file, const char *filename, std::string &str)
777{ 775{
778 File::IOFile file(filename, text_file ? "r" : "rb"); 776 FileUtil::IOFile file(filename, text_file ? "r" : "rb");
779 auto const f = file.GetHandle(); 777 auto const f = file.GetHandle();
780 778
781 if (!f) 779 if (!f)
@@ -785,6 +783,48 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str)
785 return file.ReadArray(&str[0], str.size()); 783 return file.ReadArray(&str[0], str.size());
786} 784}
787 785
786/**
787 * Splits the filename into 8.3 format
788 * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename
789 * @param filename The normal filename to use
790 * @param short_name A 9-char array in which the short name will be written
791 * @param extension A 4-char array in which the extension will be written
792 */
793void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
794 std::array<char, 4>& extension) {
795 const std::string forbidden_characters = ".\"/\\[]:;=, ";
796
797 // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces.
798 short_name = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'};
799 extension = {' ', ' ', ' ', '\0'};
800
801 std::string::size_type point = filename.rfind('.');
802 if (point == filename.size() - 1)
803 point = filename.rfind('.', point);
804
805 // Get short name.
806 int j = 0;
807 for (char letter : filename.substr(0, point)) {
808 if (forbidden_characters.find(letter, 0) != std::string::npos)
809 continue;
810 if (j == 8) {
811 // TODO(Link Mauve): also do that for filenames containing a space.
812 // TODO(Link Mauve): handle multiple files having the same short name.
813 short_name[6] = '~';
814 short_name[7] = '1';
815 break;
816 }
817 short_name[j++] = toupper(letter);
818 }
819
820 // Get extension.
821 if (point != std::string::npos) {
822 j = 0;
823 for (char letter : filename.substr(point + 1, 3))
824 extension[j++] = toupper(letter);
825 }
826}
827
788IOFile::IOFile() 828IOFile::IOFile()
789 : m_file(NULL), m_good(true) 829 : m_file(NULL), m_good(true)
790{} 830{}
@@ -826,7 +866,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
826{ 866{
827 Close(); 867 Close();
828#ifdef _WIN32 868#ifdef _WIN32
829 _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); 869 _tfopen_s(&m_file, Common::UTF8ToTStr(filename).c_str(), Common::UTF8ToTStr(openmode).c_str());
830#else 870#else
831 m_file = fopen(filename.c_str(), openmode); 871 m_file = fopen(filename.c_str(), openmode);
832#endif 872#endif
@@ -861,7 +901,7 @@ void IOFile::SetHandle(std::FILE* file)
861u64 IOFile::GetSize() 901u64 IOFile::GetSize()
862{ 902{
863 if (IsOpen()) 903 if (IsOpen())
864 return File::GetSize(m_file); 904 return FileUtil::GetSize(m_file);
865 else 905 else
866 return 0; 906 return 0;
867} 907}
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 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
7#include <fstream> 8#include <fstream>
8#include <cstdio> 9#include <cstdio>
10#include <cstring>
9#include <string> 11#include <string>
10#include <vector> 12#include <vector>
11#include <string.h>
12 13
13#include "common/common.h" 14#include "common/common.h"
14#include "common/string_util.h" 15#include "common/string_util.h"
@@ -25,6 +26,7 @@ enum {
25 D_SHADERS_IDX, 26 D_SHADERS_IDX,
26 D_STATESAVES_IDX, 27 D_STATESAVES_IDX,
27 D_SCREENSHOTS_IDX, 28 D_SCREENSHOTS_IDX,
29 D_SDMC_IDX,
28 D_HIRESTEXTURES_IDX, 30 D_HIRESTEXTURES_IDX,
29 D_DUMP_IDX, 31 D_DUMP_IDX,
30 D_DUMPFRAMES_IDX, 32 D_DUMPFRAMES_IDX,
@@ -43,10 +45,10 @@ enum {
43 NUM_PATH_INDICES 45 NUM_PATH_INDICES
44}; 46};
45 47
46namespace File 48namespace FileUtil
47{ 49{
48 50
49// FileSystem tree node/ 51// FileSystem tree node/
50struct FSTEntry 52struct FSTEntry
51{ 53{
52 bool isDirectory; 54 bool isDirectory;
@@ -84,13 +86,13 @@ bool Delete(const std::string &filename);
84// Deletes a directory filename, returns true on success 86// Deletes a directory filename, returns true on success
85bool DeleteDir(const std::string &filename); 87bool DeleteDir(const std::string &filename);
86 88
87// renames file srcFilename to destFilename, returns true on success 89// renames file srcFilename to destFilename, returns true on success
88bool Rename(const std::string &srcFilename, const std::string &destFilename); 90bool Rename(const std::string &srcFilename, const std::string &destFilename);
89 91
90// copies file srcFilename to destFilename, returns true on success 92// copies file srcFilename to destFilename, returns true on success
91bool Copy(const std::string &srcFilename, const std::string &destFilename); 93bool Copy(const std::string &srcFilename, const std::string &destFilename);
92 94
93// creates an empty file filename, returns true on success 95// creates an empty file filename, returns true on success
94bool CreateEmptyFile(const std::string &filename); 96bool CreateEmptyFile(const std::string &filename);
95 97
96// Scans the directory tree gets, starting from _Directory and adds the 98// 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);
109// Set the current directory to given directory 111// Set the current directory to given directory
110bool SetCurrentDir(const std::string &directory); 112bool SetCurrentDir(const std::string &directory);
111 113
112// Returns a pointer to a string with a Dolphin data dir in the user's home 114// Returns a pointer to a string with a Citra data dir in the user's home
113// directory. To be used in "multi-user" mode (that is, installed). 115// directory. To be used in "multi-user" mode (that is, installed).
114const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); 116const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
115 117
@@ -127,8 +129,18 @@ std::string GetBundleDirectory();
127std::string &GetExeDirectory(); 129std::string &GetExeDirectory();
128#endif 130#endif
129 131
130bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); 132size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename);
131bool ReadFileToString(bool text_file, const char *filename, std::string &str); 133size_t ReadFileToString(bool text_file, const char *filename, std::string &str);
134
135/**
136 * Splits the filename into 8.3 format
137 * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename
138 * @param filename The normal filename to use
139 * @param short_name A 9-char array in which the short name will be written
140 * @param extension A 4-char array in which the extension will be written
141 */
142void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
143 std::array<char, 4>& extension);
132 144
133// simple wrapper for cstdlib file functions to 145// simple wrapper for cstdlib file functions to
134// hopefully will make error checking easier 146// hopefully will make error checking easier
@@ -141,39 +153,51 @@ public:
141 IOFile(const std::string& filename, const char openmode[]); 153 IOFile(const std::string& filename, const char openmode[]);
142 154
143 ~IOFile(); 155 ~IOFile();
144 156
145 IOFile(IOFile&& other); 157 IOFile(IOFile&& other);
146 IOFile& operator=(IOFile&& other); 158 IOFile& operator=(IOFile&& other);
147 159
148 void Swap(IOFile& other); 160 void Swap(IOFile& other);
149 161
150 bool Open(const std::string& filename, const char openmode[]); 162 bool Open(const std::string& filename, const char openmode[]);
151 bool Close(); 163 bool Close();
152 164
153 template <typename T> 165 template <typename T>
154 bool ReadArray(T* data, size_t length) 166 size_t ReadArray(T* data, size_t length)
155 { 167 {
156 if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) 168 if (!IsOpen()) {
157 m_good = false; 169 m_good = false;
170 return -1;
171 }
158 172
159 return m_good; 173 size_t items_read = std::fread(data, sizeof(T), length, m_file);
174 if (items_read != length)
175 m_good = false;
176
177 return items_read;
160 } 178 }
161 179
162 template <typename T> 180 template <typename T>
163 bool WriteArray(const T* data, size_t length) 181 size_t WriteArray(const T* data, size_t length)
164 { 182 {
165 if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) 183 if (!IsOpen()) {
184 m_good = false;
185 return -1;
186 }
187
188 size_t items_written = std::fwrite(data, sizeof(T), length, m_file);
189 if (items_written != length)
166 m_good = false; 190 m_good = false;
167 191
168 return m_good; 192 return items_written;
169 } 193 }
170 194
171 bool ReadBytes(void* data, size_t length) 195 size_t ReadBytes(void* data, size_t length)
172 { 196 {
173 return ReadArray(reinterpret_cast<char*>(data), length); 197 return ReadArray(reinterpret_cast<char*>(data), length);
174 } 198 }
175 199
176 bool WriteBytes(const void* data, size_t length) 200 size_t WriteBytes(const void* data, size_t length)
177 { 201 {
178 return WriteArray(reinterpret_cast<const char*>(data), length); 202 return WriteArray(reinterpret_cast<const char*>(data), length);
179 } 203 }
@@ -213,7 +237,7 @@ template <typename T>
213void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) 237void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode)
214{ 238{
215#ifdef _WIN32 239#ifdef _WIN32
216 fstream.open(UTF8ToTStr(filename).c_str(), openmode); 240 fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode);
217#else 241#else
218 fstream.open(filename.c_str(), openmode); 242 fstream.open(filename.c_str(), openmode);
219#endif 243#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 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the
8// real STL classes.
9
10// Not fully featured, no safety checking yet. Add features as needed.
11
12// TODO: "inline" storage?
13
14template <class T, int N>
15class fixed_size_queue.h
16{
17 T *storage;
18 int head;
19 int tail;
20 int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future.
21
22 // Make copy constructor private for now.
23 fixed_size_queue.h(fixed_size_queue.h &other) { }
24
25public:
26 fixed_size_queue.h()
27 {
28 storage = new T[N];
29 clear();
30 }
31
32 ~fixed_size_queue.h()
33 {
34 delete [] storage;
35 }
36
37 void clear() {
38 head = 0;
39 tail = 0;
40 count = 0;
41 }
42
43 void push(T t) {
44 storage[tail] = t;
45 tail++;
46 if (tail == N)
47 tail = 0;
48 count++;
49 }
50
51 void pop() {
52 head++;
53 if (head == N)
54 head = 0;
55 count--;
56 }
57
58 T pop_front() {
59 const T &temp = storage[head];
60 pop();
61 return temp;
62 }
63
64 T &front() { return storage[head]; }
65 const T &front() const { return storage[head]; }
66
67 size_t size() const {
68 return count;
69 }
70};
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "key_map.h"
6#include <map>
7
8namespace KeyMap {
9
10static std::map<HostDeviceKey, HID_User::PadState> key_map;
11static int next_device_id = 0;
12
13int NewDeviceId() {
14 return next_device_id++;
15}
16
17void SetKeyMapping(HostDeviceKey key, HID_User::PadState padState) {
18 key_map[key].hex = padState.hex;
19}
20
21HID_User::PadState GetPadKey(HostDeviceKey key) {
22 return key_map[key];
23}
24
25}
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/hid_user.h"
8
9namespace KeyMap {
10
11/**
12 * Represents a key for a specific host device.
13 */
14struct HostDeviceKey {
15 int key_code;
16 int device_id; ///< Uniquely identifies a host device
17
18 bool operator < (const HostDeviceKey &other) const {
19 if (device_id == other.device_id) {
20 return key_code < other.key_code;
21 }
22 return device_id < other.device_id;
23 }
24
25 bool operator == (const HostDeviceKey &other) const {
26 return device_id == other.device_id && key_code == other.key_code;
27 }
28};
29
30/**
31 * Generates a new device id, which uniquely identifies a host device within KeyMap.
32 */
33int NewDeviceId();
34
35/**
36 * Maps a device-specific key to a PadState.
37 */
38void SetKeyMapping(HostDeviceKey key, HID_User::PadState padState);
39
40/**
41 * Gets the PadState that's mapped to the provided device-specific key.
42 */
43HID_User::PadState GetPadKey(HostDeviceKey key);
44
45}
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 {
28 COMMANDPROCESSOR, 28 COMMANDPROCESSOR,
29 COMMON, 29 COMMON,
30 CONSOLE, 30 CONSOLE,
31 CONFIG,
31 DISCIO, 32 DISCIO,
32 FILEMON, 33 FILEMON,
33 DSPHLE, 34 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 @@
8#include "common/console_listener.h" 8#include "common/console_listener.h"
9#include "common/timer.h" 9#include "common/timer.h"
10#include "common/thread.h" 10#include "common/thread.h"
11#include "common/file_util.h"
12 11
13void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, 12void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
14 const char* function, const char* fmt, ...) 13 const char* function, const char* fmt, ...)
@@ -31,6 +30,7 @@ LogManager::LogManager()
31 m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); 30 m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log");
32 m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); 31 m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot");
33 m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); 32 m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common");
33 m_Log[LogTypes::CONFIG] = new LogContainer("CONFIG", "Configuration");
34 m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); 34 m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO");
35 m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); 35 m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor");
36 m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); 36 m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad");
@@ -76,7 +76,7 @@ LogManager::LogManager()
76 m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); 76 m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager");
77 m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); 77 m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay");
78 78
79 m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); 79 m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str());
80 m_consoleLog = new ConsoleListener(); 80 m_consoleLog = new ConsoleListener();
81 m_debuggerLog = new DebuggerLogListener(); 81 m_debuggerLog = new DebuggerLogListener();
82 82
@@ -121,7 +121,7 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const
121 if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) 121 if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
122 return; 122 return;
123 123
124 CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); 124 Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args);
125 125
126 static const char level_to_char[7] = "ONEWID"; 126 static const char level_to_char[7] = "ONEWID";
127 sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, 127 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
30public: 30public:
31 FileLogListener(const char *filename); 31 FileLogListener(const char *filename);
32 32
33 void Log(LogTypes::LOG_LEVELS, const char *msg); 33 void Log(LogTypes::LOG_LEVELS, const char *msg) override;
34 34
35 bool IsValid() { return !m_logfile.fail(); } 35 bool IsValid() { return !m_logfile.fail(); }
36 bool IsEnabled() const { return m_enable; } 36 bool IsEnabled() const { return m_enable; }
@@ -47,7 +47,7 @@ private:
47class DebuggerLogListener : public LogListener 47class DebuggerLogListener : public LogListener
48{ 48{
49public: 49public:
50 void Log(LogTypes::LOG_LEVELS, const char *msg); 50 void Log(LogTypes::LOG_LEVELS, const char *msg) override;
51}; 51};
52 52
53class LogContainer 53class 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 @@
6#include "common/common.h" 6#include "common/common.h"
7#include "common/math_util.h" 7#include "common/math_util.h"
8 8
9#include <cmath> 9#include <numeric> // Necessary on OS X, but not Linux
10#include <numeric>
11 10
12namespace MathUtil 11namespace MathUtil
13{ 12{
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 @@
22#include "common/string_util.h" 22#include "common/string_util.h"
23 23
24#ifndef _WIN32 24#ifndef _WIN32
25#include <sys/stat.h>
26#include <fcntl.h> 25#include <fcntl.h>
27#include <unistd.h>
28#include <cerrno>
29#include <cstring>
30#ifdef ANDROID 26#ifdef ANDROID
31#include <sys/ioctl.h> 27#include <sys/ioctl.h>
32#include <linux/ashmem.h> 28#include <linux/ashmem.h>
@@ -143,7 +139,7 @@ void MemArena::GrabLowMemSpace(size_t size)
143 // a bit more. 139 // a bit more.
144 for (int i = 0; i < 10000; i++) 140 for (int i = 0; i < 10000; i++)
145 { 141 {
146 std::string file_name = StringFromFormat("/citramem.%d", i); 142 std::string file_name = Common::StringFromFormat("/citramem.%d", i);
147 fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); 143 fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600);
148 if (fd != -1) 144 if (fd != -1)
149 { 145 {
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 @@
10#ifdef _WIN32 10#ifdef _WIN32
11#include <windows.h> 11#include <windows.h>
12#include <psapi.h> 12#include <psapi.h>
13#else
14#include <cerrno>
15#include <cstdio>
16#endif 13#endif
17 14
18#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) 15#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
@@ -190,7 +187,7 @@ std::string MemUsage()
190 if (NULL == hProcess) return "MemUsage Error"; 187 if (NULL == hProcess) return "MemUsage Error";
191 188
192 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) 189 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
193 Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); 190 Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
194 191
195 CloseHandle(hProcess); 192 CloseHandle(hProcess);
196 return Ret; 193 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, ...)
72 72
73 va_list args; 73 va_list args;
74 va_start(args, format); 74 va_start(args, format);
75 CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); 75 Common::CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args);
76 va_end(args); 76 va_end(args);
77 77
78 ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); 78 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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstdlib>
7#include <cstdio>
8 6
9#include "common/common.h" 7#include "common/common.h"
10#include "common/common_paths.h"
11#include "common/string_util.h" 8#include "common/string_util.h"
12 9
13#ifdef _WIN32 10#ifdef _WIN32
14 #include <Windows.h> 11 #include <Windows.h>
12 #include <codecvt>
15#else 13#else
16 #include <cerrno>
17 #include <iconv.h> 14 #include <iconv.h>
18#endif 15#endif
19 16
17namespace Common {
18
20/// Make a string lowercase 19/// Make a string lowercase
21void LowerStr(char* str) { 20std::string ToLower(std::string str) {
22 for (int i = 0; str[i]; i++) { 21 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
23 str[i] = tolower(str[ i ]); 22 return str;
24 }
25} 23}
26 24
27/// Make a string uppercase 25/// Make a string uppercase
28void UpperStr(char* str) { 26std::string ToUpper(std::string str) {
29 for (int i=0; i < strlen(str); i++) { 27 std::transform(str.begin(), str.end(), str.begin(), ::toupper);
30 if(str[i] >= 'a' && str[i] <= 'z') { 28 return str;
31 str[i] &= 0xDF;
32 }
33 }
34} 29}
35 30
36// faster than sscanf 31// faster than sscanf
@@ -192,9 +187,9 @@ bool TryParse(const std::string &str, u32 *const output)
192 187
193bool TryParse(const std::string &str, bool *const output) 188bool TryParse(const std::string &str, bool *const output)
194{ 189{
195 if ("1" == str || !strcasecmp("true", str.c_str())) 190 if ("1" == str || "true" == ToLower(str))
196 *output = true; 191 *output = true;
197 else if ("0" == str || !strcasecmp("false", str.c_str())) 192 else if ("0" == str || "false" == ToLower(str))
198 *output = false; 193 *output = false;
199 else 194 else
200 return false; 195 return false;
@@ -202,13 +197,6 @@ bool TryParse(const std::string &str, bool *const output)
202 return true; 197 return true;
203} 198}
204 199
205std::string StringFromInt(int value)
206{
207 char temp[16];
208 sprintf(temp, "%i", value);
209 return temp;
210}
211
212std::string StringFromBool(bool value) 200std::string StringFromBool(bool value)
213{ 201{
214 return value ? "True" : "False"; 202 return value ? "True" : "False";
@@ -283,12 +271,17 @@ std::string TabsToSpaces(int tab_size, const std::string &in)
283 271
284std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) 272std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest)
285{ 273{
286 while(1) 274 size_t pos = 0;
275
276 if (src == dest)
277 return result;
278
279 while ((pos = result.find(src, pos)) != std::string::npos)
287 { 280 {
288 size_t pos = result.find(src);
289 if (pos == std::string::npos) break;
290 result.replace(pos, src.size(), dest); 281 result.replace(pos, src.size(), dest);
282 pos += dest.length();
291 } 283 }
284
292 return result; 285 return result;
293} 286}
294 287
@@ -419,7 +412,19 @@ std::string UriEncode(const std::string & sSrc)
419 412
420#ifdef _WIN32 413#ifdef _WIN32
421 414
422std::string UTF16ToUTF8(const std::wstring& input) 415std::string UTF16ToUTF8(const std::u16string& input)
416{
417 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
418 return convert.to_bytes(input);
419}
420
421std::u16string UTF8ToUTF16(const std::string& input)
422{
423 std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
424 return convert.from_bytes(input);
425}
426
427static std::string UTF16ToUTF8(const std::wstring& input)
423{ 428{
424 auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); 429 auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr);
425 430
@@ -432,7 +437,7 @@ std::string UTF16ToUTF8(const std::wstring& input)
432 return output; 437 return output;
433} 438}
434 439
435std::wstring CPToUTF16(u32 code_page, const std::string& input) 440static std::wstring CPToUTF16(u32 code_page, const std::string& input)
436{ 441{
437 auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); 442 auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0);
438 443
@@ -445,7 +450,7 @@ std::wstring CPToUTF16(u32 code_page, const std::string& input)
445 return output; 450 return output;
446} 451}
447 452
448std::wstring UTF8ToUTF16(const std::string& input) 453std::wstring UTF8ToUTF16W(const std::string &input)
449{ 454{
450 return CPToUTF16(CP_UTF8, input); 455 return CPToUTF16(CP_UTF8, input);
451} 456}
@@ -463,61 +468,123 @@ std::string CP1252ToUTF8(const std::string& input)
463#else 468#else
464 469
465template <typename T> 470template <typename T>
466std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) 471static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
467{ 472{
468 std::string result; 473 std::string result;
469 474
470 iconv_t const conv_desc = iconv_open("UTF-8", fromcode); 475 iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
471 if ((iconv_t)-1 == conv_desc) 476 if ((iconv_t)(-1) == conv_desc)
472 { 477 {
473 ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); 478 ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
479 iconv_close(conv_desc);
480 return {};
474 } 481 }
475 else
476 {
477 size_t const in_bytes = sizeof(T) * input.size();
478 size_t const out_buffer_size = 4 * in_bytes;
479 482
480 std::string out_buffer; 483 const size_t in_bytes = sizeof(T) * input.size();
481 out_buffer.resize(out_buffer_size); 484 // Multiply by 4, which is the max number of bytes to encode a codepoint
485 const size_t out_buffer_size = 4 * in_bytes;
482 486
483 auto src_buffer = &input[0]; 487 std::string out_buffer;
484 size_t src_bytes = in_bytes; 488 out_buffer.resize(out_buffer_size);
485 auto dst_buffer = &out_buffer[0];
486 size_t dst_bytes = out_buffer.size();
487 489
488 while (src_bytes != 0) 490 auto src_buffer = &input[0];
489 { 491 size_t src_bytes = in_bytes;
490 size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, 492 auto dst_buffer = &out_buffer[0];
491 &dst_buffer, &dst_bytes); 493 size_t dst_bytes = out_buffer.size();
494
495 while (0 != src_bytes)
496 {
497 size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
498 &dst_buffer, &dst_bytes);
492 499
493 if ((size_t)-1 == iconv_result) 500 if (static_cast<size_t>(-1) == iconv_result)
501 {
502 if (EILSEQ == errno || EINVAL == errno)
494 { 503 {
495 if (EILSEQ == errno || EINVAL == errno) 504 // Try to skip the bad character
505 if (0 != src_bytes)
496 { 506 {
497 // Try to skip the bad character 507 --src_bytes;
498 if (src_bytes != 0) 508 ++src_buffer;
499 {
500 --src_bytes;
501 ++src_buffer;
502 }
503 }
504 else
505 {
506 ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno));
507 break;
508 } 509 }
509 } 510 }
511 else
512 {
513 ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno));
514 break;
515 }
510 } 516 }
517 }
511 518
512 out_buffer.resize(out_buffer_size - dst_bytes); 519 out_buffer.resize(out_buffer_size - dst_bytes);
513 out_buffer.swap(result); 520 out_buffer.swap(result);
514 521
522 iconv_close(conv_desc);
523
524 return result;
525}
526
527std::u16string UTF8ToUTF16(const std::string& input)
528{
529 std::u16string result;
530
531 iconv_t const conv_desc = iconv_open("UTF-16", "UTF-8");
532 if ((iconv_t)(-1) == conv_desc)
533 {
534 ERROR_LOG(COMMON, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
515 iconv_close(conv_desc); 535 iconv_close(conv_desc);
536 return {};
537 }
538
539 const size_t in_bytes = sizeof(char) * input.size();
540 // Multiply by 4, which is the max number of bytes to encode a codepoint
541 const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes;
542
543 std::u16string out_buffer;
544 out_buffer.resize(out_buffer_size);
545
546 char* src_buffer = const_cast<char*>(&input[0]);
547 size_t src_bytes = in_bytes;
548 char* dst_buffer = (char*)(&out_buffer[0]);
549 size_t dst_bytes = out_buffer.size();
550
551 while (0 != src_bytes)
552 {
553 size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes,
554 &dst_buffer, &dst_bytes);
555
556 if (static_cast<size_t>(-1) == iconv_result)
557 {
558 if (EILSEQ == errno || EINVAL == errno)
559 {
560 // Try to skip the bad character
561 if (0 != src_bytes)
562 {
563 --src_bytes;
564 ++src_buffer;
565 }
566 }
567 else
568 {
569 ERROR_LOG(COMMON, "iconv failure [UTF-8]: %s", strerror(errno));
570 break;
571 }
572 }
516 } 573 }
574
575 out_buffer.resize(out_buffer_size - dst_bytes);
576 out_buffer.swap(result);
577
578 iconv_close(conv_desc);
517 579
518 return result; 580 return result;
519} 581}
520 582
583std::string UTF16ToUTF8(const std::u16string& input)
584{
585 return CodeToUTF8("UTF-16", input);
586}
587
521std::string CP1252ToUTF8(const std::string& input) 588std::string CP1252ToUTF8(const std::string& input)
522{ 589{
523 //return CodeToUTF8("CP1252//TRANSLIT", input); 590 //return CodeToUTF8("CP1252//TRANSLIT", input);
@@ -531,17 +598,6 @@ std::string SHIFTJISToUTF8(const std::string& input)
531 return CodeToUTF8("SJIS", input); 598 return CodeToUTF8("SJIS", input);
532} 599}
533 600
534std::string UTF16ToUTF8(const std::wstring& input)
535{
536 std::string result =
537 // CodeToUTF8("UCS-2", input);
538 // CodeToUTF8("UCS-2LE", input);
539 // CodeToUTF8("UTF-16", input);
540 CodeToUTF8("UTF-16LE", input);
541
542 // TODO: why is this needed?
543 result.erase(std::remove(result.begin(), result.end(), 0x00), result.end());
544 return result;
545}
546
547#endif 601#endif
602
603}
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 @@
12 12
13#include "common/common.h" 13#include "common/common.h"
14 14
15namespace Common {
16
15/// Make a string lowercase 17/// Make a string lowercase
16void LowerStr(char* str); 18std::string ToLower(std::string str);
17 19
18/// Make a string uppercase 20/// Make a string uppercase
19void UpperStr(char* str); 21std::string ToUpper(std::string str);
20 22
21std::string StringFromFormat(const char* format, ...); 23std::string StringFromFormat(const char* format, ...);
22// Cheap! 24// Cheap!
@@ -52,7 +54,6 @@ std::string ThousandSeparate(I value, int spaces = 0)
52 return oss.str(); 54 return oss.str();
53} 55}
54 56
55std::string StringFromInt(int value);
56std::string StringFromBool(bool value); 57std::string StringFromBool(bool value);
57 58
58bool TryParse(const std::string &str, bool *output); 59bool TryParse(const std::string &str, bool *output);
@@ -88,20 +89,22 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
88std::string UriDecode(const std::string & sSrc); 89std::string UriDecode(const std::string & sSrc);
89std::string UriEncode(const std::string & sSrc); 90std::string UriEncode(const std::string & sSrc);
90 91
92std::string UTF16ToUTF8(const std::u16string& input);
93std::u16string UTF8ToUTF16(const std::string& input);
94
91std::string CP1252ToUTF8(const std::string& str); 95std::string CP1252ToUTF8(const std::string& str);
92std::string SHIFTJISToUTF8(const std::string& str); 96std::string SHIFTJISToUTF8(const std::string& str);
93std::string UTF16ToUTF8(const std::wstring& str);
94 97
95#ifdef _WIN32 98#ifdef _WIN32
96 99
97std::wstring UTF8ToUTF16(const std::string& str); 100std::wstring UTF8ToUTF16W(const std::string& str);
98 101
99#ifdef _UNICODE 102#ifdef _UNICODE
100inline std::string TStrToUTF8(const std::wstring& str) 103inline std::string TStrToUTF8(const std::wstring& str)
101{ return UTF16ToUTF8(str); } 104{ return UTF16ToUTF8(str); }
102 105
103inline std::wstring UTF8ToTStr(const std::string& str) 106inline std::wstring UTF8ToTStr(const std::string& str)
104{ return UTF8ToUTF16(str); } 107{ return UTF8ToUTF16W(str); }
105#else 108#else
106inline std::string TStrToUTF8(const std::string& str) 109inline std::string TStrToUTF8(const std::string& str)
107{ return str; } 110{ return str; }
@@ -111,3 +114,5 @@ inline std::string UTF8ToTStr(const std::string& str)
111#endif 114#endif
112 115
113#endif 116#endif
117
118}
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:
85 return *this; 85 return *this;
86 } 86 }
87 87
88 operator long() const { return (long)swap(); }
89 operator s8() const { return (s8)swap(); } 88 operator s8() const { return (s8)swap(); }
90 operator u8() const { return (u8)swap(); } 89 operator u8() const { return (u8)swap(); }
91 operator s16() const { return (s16)swap(); } 90 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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/thread.h" 5#include "common/thread.h"
6#include "common/common.h"
7 6
8#ifdef __APPLE__ 7#ifdef __APPLE__
9#include <mach/mach.h> 8#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()
169{ 169{
170 time_t sysTime; 170 time_t sysTime;
171 struct tm * gmTime; 171 struct tm * gmTime;
172 char formattedTime[13];
173 char tmp[13]; 172 char tmp[13];
174 173
175 time(&sysTime); 174 time(&sysTime);
@@ -181,14 +180,12 @@ std::string Timer::GetTimeFormatted()
181#ifdef _WIN32 180#ifdef _WIN32
182 struct timeb tp; 181 struct timeb tp;
183 (void)::ftime(&tp); 182 (void)::ftime(&tp);
184 sprintf(formattedTime, "%s:%03i", tmp, tp.millitm); 183 return StringFromFormat("%s:%03i", tmp, tp.millitm);
185#else 184#else
186 struct timeval t; 185 struct timeval t;
187 (void)gettimeofday(&t, NULL); 186 (void)gettimeofday(&t, NULL);
188 sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); 187 return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000));
189#endif 188#endif
190
191 return std::string(formattedTime);
192} 189}
193 190
194// Returns a timestamp with decimals for precise time comparisons 191// 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 @@
19#endif 19#endif
20 20
21#include <cstdlib> 21#include <cstdlib>
22#include <cstdio>
23#include <cstring> 22#include <cstring>
24#include <cstdarg>
25
26#include <algorithm> 23#include <algorithm>
27#include <string>
28 24
29#include "common/common_types.h" 25#include "common/common_types.h"
30#include "common/utf8.h" 26#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 @@
1set(SRCS 1set(SRCS
2 arm/disassembler/arm_disasm.cpp 2 arm/disassembler/arm_disasm.cpp
3 arm/disassembler/load_symbol_map.cpp 3 arm/disassembler/load_symbol_map.cpp
4 arm/interpreter/mmu/arm1176jzf_s_mmu.cpp 4 arm/dyncom/arm_dyncom.cpp
5 arm/interpreter/mmu/cache.cpp 5 arm/dyncom/arm_dyncom_dec.cpp
6 arm/interpreter/mmu/maverick.cpp 6 arm/dyncom/arm_dyncom_interpreter.cpp
7 arm/interpreter/mmu/rb.cpp 7 arm/dyncom/arm_dyncom_run.cpp
8 arm/interpreter/mmu/sa_mmu.cpp 8 arm/dyncom/arm_dyncom_thumb.cpp
9 arm/interpreter/mmu/tlb.cpp
10 arm/interpreter/mmu/wb.cpp
11 arm/interpreter/mmu/xscale_copro.cpp
12 arm/interpreter/vfp/vfp.cpp
13 arm/interpreter/vfp/vfpdouble.cpp
14 arm/interpreter/vfp/vfpinstr.cpp
15 arm/interpreter/vfp/vfpsingle.cpp
16 arm/interpreter/arm_interpreter.cpp 9 arm/interpreter/arm_interpreter.cpp
17 arm/interpreter/armcopro.cpp 10 arm/interpreter/armcopro.cpp
18 arm/interpreter/armemu.cpp 11 arm/interpreter/armemu.cpp
19 arm/interpreter/arminit.cpp 12 arm/interpreter/arminit.cpp
20 arm/interpreter/armmmu.cpp
21 arm/interpreter/armos.cpp
22 arm/interpreter/armsupp.cpp 13 arm/interpreter/armsupp.cpp
23 arm/interpreter/armvirt.cpp 14 arm/interpreter/armvirt.cpp
24 arm/interpreter/thumbemu.cpp 15 arm/interpreter/thumbemu.cpp
16 arm/skyeye_common/vfp/vfp.cpp
17 arm/skyeye_common/vfp/vfpdouble.cpp
18 arm/skyeye_common/vfp/vfpinstr.cpp
19 arm/skyeye_common/vfp/vfpsingle.cpp
25 file_sys/archive_romfs.cpp 20 file_sys/archive_romfs.cpp
21 file_sys/archive_sdmc.cpp
22 file_sys/file_romfs.cpp
23 file_sys/file_sdmc.cpp
24 file_sys/directory_romfs.cpp
25 file_sys/directory_sdmc.cpp
26 hle/kernel/address_arbiter.cpp 26 hle/kernel/address_arbiter.cpp
27 hle/kernel/archive.cpp 27 hle/kernel/archive.cpp
28 hle/kernel/event.cpp 28 hle/kernel/event.cpp
@@ -30,15 +30,24 @@ set(SRCS
30 hle/kernel/mutex.cpp 30 hle/kernel/mutex.cpp
31 hle/kernel/shared_memory.cpp 31 hle/kernel/shared_memory.cpp
32 hle/kernel/thread.cpp 32 hle/kernel/thread.cpp
33 hle/service/apt.cpp 33 hle/service/ac_u.cpp
34 hle/service/fs.cpp 34 hle/service/apt_u.cpp
35 hle/service/gsp.cpp 35 hle/service/cfg_u.cpp
36 hle/service/hid.cpp 36 hle/service/dsp_dsp.cpp
37 hle/service/ndm.cpp 37 hle/service/err_f.cpp
38 hle/service/fs_user.cpp
39 hle/service/frd_u.cpp
40 hle/service/gsp_gpu.cpp
41 hle/service/hid_user.cpp
42 hle/service/mic_u.cpp
43 hle/service/ndm_u.cpp
44 hle/service/nwm_uds.cpp
45 hle/service/ptm_u.cpp
38 hle/service/service.cpp 46 hle/service/service.cpp
47 hle/service/soc_u.cpp
39 hle/service/srv.cpp 48 hle/service/srv.cpp
49 hle/service/ssl_c.cpp
40 hle/config_mem.cpp 50 hle/config_mem.cpp
41 hle/coprocessor.cpp
42 hle/hle.cpp 51 hle/hle.cpp
43 hle/svc.cpp 52 hle/svc.cpp
44 hw/gpu.cpp 53 hw/gpu.cpp
@@ -51,32 +60,40 @@ set(SRCS
51 core_timing.cpp 60 core_timing.cpp
52 mem_map.cpp 61 mem_map.cpp
53 mem_map_funcs.cpp 62 mem_map_funcs.cpp
63 settings.cpp
54 system.cpp 64 system.cpp
55 ) 65 )
56 66
57set(HEADERS 67set(HEADERS
58 arm/disassembler/arm_disasm.h 68 arm/disassembler/arm_disasm.h
59 arm/disassembler/load_symbol_map.h 69 arm/disassembler/load_symbol_map.h
60 arm/interpreter/mmu/arm1176jzf_s_mmu.h 70 arm/dyncom/arm_dyncom.h
61 arm/interpreter/mmu/cache.h 71 arm/dyncom/arm_dyncom_dec.h
62 arm/interpreter/mmu/rb.h 72 arm/dyncom/arm_dyncom_interpreter.h
63 arm/interpreter/mmu/sa_mmu.h 73 arm/dyncom/arm_dyncom_run.h
64 arm/interpreter/mmu/tlb.h 74 arm/dyncom/arm_dyncom_thumb.h
65 arm/interpreter/mmu/wb.h
66 arm/interpreter/vfp/asm_vfp.h
67 arm/interpreter/vfp/vfp.h
68 arm/interpreter/vfp/vfp_helper.h
69 arm/interpreter/arm_interpreter.h 75 arm/interpreter/arm_interpreter.h
70 arm/interpreter/arm_regformat.h 76 arm/skyeye_common/arm_regformat.h
71 arm/interpreter/armcpu.h 77 arm/skyeye_common/armcpu.h
72 arm/interpreter/armdefs.h 78 arm/skyeye_common/armdefs.h
73 arm/interpreter/armemu.h 79 arm/skyeye_common/armemu.h
74 arm/interpreter/armmmu.h 80 arm/skyeye_common/armmmu.h
75 arm/interpreter/armos.h 81 arm/skyeye_common/armos.h
76 arm/interpreter/skyeye_defs.h 82 arm/skyeye_common/skyeye_defs.h
83 arm/skyeye_common/skyeye_types.h
84 arm/skyeye_common/vfp/asm_vfp.h
85 arm/skyeye_common/vfp/vfp.h
86 arm/skyeye_common/vfp/vfp_helper.h
77 arm/arm_interface.h 87 arm/arm_interface.h
78 file_sys/archive.h 88 file_sys/archive.h
79 file_sys/archive_romfs.h 89 file_sys/archive_romfs.h
90 file_sys/archive_sdmc.h
91 file_sys/file.h
92 file_sys/file_romfs.h
93 file_sys/file_sdmc.h
94 file_sys/directory.h
95 file_sys/directory_romfs.h
96 file_sys/directory_sdmc.h
80 hle/kernel/address_arbiter.h 97 hle/kernel/address_arbiter.h
81 hle/kernel/archive.h 98 hle/kernel/archive.h
82 hle/kernel/event.h 99 hle/kernel/event.h
@@ -84,15 +101,24 @@ set(HEADERS
84 hle/kernel/mutex.h 101 hle/kernel/mutex.h
85 hle/kernel/shared_memory.h 102 hle/kernel/shared_memory.h
86 hle/kernel/thread.h 103 hle/kernel/thread.h
87 hle/service/apt.h 104 hle/service/ac_u.h
88 hle/service/fs.h 105 hle/service/apt_u.h
89 hle/service/gsp.h 106 hle/service/cfg_u.h
90 hle/service/hid.h 107 hle/service/dsp_dsp.h
91 hle/service/ndm.h 108 hle/service/err_f.h
109 hle/service/fs_user.h
110 hle/service/frd_u.h
111 hle/service/gsp_gpu.h
112 hle/service/hid_user.h
113 hle/service/mic_u.h
114 hle/service/ndm_u.h
115 hle/service/nwm_uds.h
116 hle/service/ptm_u.h
92 hle/service/service.h 117 hle/service/service.h
118 hle/service/soc_u.h
93 hle/service/srv.h 119 hle/service/srv.h
120 hle/service/ssl_c.h
94 hle/config_mem.h 121 hle/config_mem.h
95 hle/coprocessor.h
96 hle/function_wrappers.h 122 hle/function_wrappers.h
97 hle/hle.h 123 hle/hle.h
98 hle/svc.h 124 hle/svc.h
@@ -105,6 +131,7 @@ set(HEADERS
105 core.h 131 core.h
106 core_timing.h 132 core_timing.h
107 mem_map.h 133 mem_map.h
134 settings.h
108 system.h 135 system.h
109 ) 136 )
110 137
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)
260 // The "mov" instruction ignores the first operand (rn). 260 // The "mov" instruction ignores the first operand (rn).
261 rn_str[0] = 0; 261 rn_str[0] = 0;
262 if ((flags & kNoOperand1) == 0) { 262 if ((flags & kNoOperand1) == 0) {
263 rn_str = StringFromFormat("r%d, ", rn); 263 rn_str = Common::StringFromFormat("r%d, ", rn);
264 } 264 }
265 265
266 // The following instructions do not write the result register (rd): 266 // The following instructions do not write the result register (rd):
267 // tst, teq, cmp, cmn. 267 // tst, teq, cmp, cmn.
268 rd_str[0] = 0; 268 rd_str[0] = 0;
269 if ((flags & kNoDest) == 0) { 269 if ((flags & kNoDest) == 0) {
270 rd_str = StringFromFormat("r%d, ", rd); 270 rd_str = Common::StringFromFormat("r%d, ", rd);
271 } 271 }
272 272
273 const char *sbit_str = ""; 273 const char *sbit_str = "";
@@ -275,7 +275,7 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn)
275 sbit_str = "s"; 275 sbit_str = "s";
276 276
277 if (is_immed) { 277 if (is_immed) {
278 return StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x", 278 return Common::StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x",
279 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed); 279 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed);
280 } 280 }
281 281
@@ -290,24 +290,24 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn)
290 rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); 290 rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2));
291 291
292 if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { 292 if (!shift_is_reg && shift_type == 0 && shift_amount == 0) {
293 return StringFromFormat("%s%s%s\t%s%sr%d", 293 return Common::StringFromFormat("%s%s%s\t%s%sr%d",
294 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm); 294 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm);
295 } 295 }
296 296
297 const char *shift_name = shift_names[shift_type]; 297 const char *shift_name = shift_names[shift_type];
298 if (shift_is_reg) { 298 if (shift_is_reg) {
299 return StringFromFormat("%s%s%s\t%s%sr%d, %s r%d", 299 return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s r%d",
300 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm, 300 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm,
301 shift_name, rs); 301 shift_name, rs);
302 } 302 }
303 if (shift_amount == 0) { 303 if (shift_amount == 0) {
304 if (shift_type == 3) { 304 if (shift_type == 3) {
305 return StringFromFormat("%s%s%s\t%s%sr%d, RRX", 305 return Common::StringFromFormat("%s%s%s\t%s%sr%d, RRX",
306 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm); 306 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm);
307 } 307 }
308 shift_amount = 32; 308 shift_amount = 32;
309 } 309 }
310 return StringFromFormat("%s%s%s\t%s%sr%d, %s #%u", 310 return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s #%u",
311 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm, 311 opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm,
312 shift_name, shift_amount); 312 shift_name, shift_amount);
313} 313}
@@ -325,20 +325,20 @@ std::string ARM_Disasm::DisassembleBranch(uint32_t addr, Opcode opcode, uint32_t
325 offset += 8; 325 offset += 8;
326 addr += offset; 326 addr += offset;
327 const char *opname = opcode_names[opcode]; 327 const char *opname = opcode_names[opcode];
328 return StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr); 328 return Common::StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr);
329} 329}
330 330
331std::string ARM_Disasm::DisassembleBX(uint32_t insn) 331std::string ARM_Disasm::DisassembleBX(uint32_t insn)
332{ 332{
333 uint8_t cond = (insn >> 28) & 0xf; 333 uint8_t cond = (insn >> 28) & 0xf;
334 uint8_t rn = insn & 0xf; 334 uint8_t rn = insn & 0xf;
335 return StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn); 335 return Common::StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn);
336} 336}
337 337
338std::string ARM_Disasm::DisassembleBKPT(uint32_t insn) 338std::string ARM_Disasm::DisassembleBKPT(uint32_t insn)
339{ 339{
340 uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); 340 uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf);
341 return StringFromFormat("bkpt\t#%d", immed); 341 return Common::StringFromFormat("bkpt\t#%d", immed);
342} 342}
343 343
344std::string ARM_Disasm::DisassembleCLZ(uint32_t insn) 344std::string ARM_Disasm::DisassembleCLZ(uint32_t insn)
@@ -346,7 +346,7 @@ std::string ARM_Disasm::DisassembleCLZ(uint32_t insn)
346 uint8_t cond = (insn >> 28) & 0xf; 346 uint8_t cond = (insn >> 28) & 0xf;
347 uint8_t rd = (insn >> 12) & 0xf; 347 uint8_t rd = (insn >> 12) & 0xf;
348 uint8_t rm = insn & 0xf; 348 uint8_t rm = insn & 0xf;
349 return StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); 349 return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm);
350} 350}
351 351
352std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) 352std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn)
@@ -376,7 +376,7 @@ std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn)
376 tmp_list[0] = 0; 376 tmp_list[0] = 0;
377 for (int ii = 0; ii < 16; ++ii) { 377 for (int ii = 0; ii < 16; ++ii) {
378 if (reg_list & (1 << ii)) { 378 if (reg_list & (1 << ii)) {
379 tmp_list += StringFromFormat("%sr%d", comma, ii); 379 tmp_list += Common::StringFromFormat("%sr%d", comma, ii);
380 comma = ","; 380 comma = ",";
381 } 381 }
382 } 382 }
@@ -396,7 +396,7 @@ std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn)
396 } 396 }
397 } 397 }
398 398
399 return StringFromFormat("%s%s%s\tr%d%s, {%s}%s", 399 return Common::StringFromFormat("%s%s%s\tr%d%s, {%s}%s",
400 opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list.c_str(), carret); 400 opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list.c_str(), carret);
401} 401}
402 402
@@ -432,10 +432,10 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn)
432 if (is_reg == 0) { 432 if (is_reg == 0) {
433 if (is_pre) { 433 if (is_pre) {
434 if (offset == 0) { 434 if (offset == 0) {
435 return StringFromFormat("%s%s%s\tr%d, [r%d]", 435 return Common::StringFromFormat("%s%s%s\tr%d, [r%d]",
436 opname, cond_to_str(cond), byte, rd, rn); 436 opname, cond_to_str(cond), byte, rd, rn);
437 } else { 437 } else {
438 return StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", 438 return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s",
439 opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang); 439 opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang);
440 } 440 }
441 } else { 441 } else {
@@ -443,7 +443,7 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn)
443 if (write_back) 443 if (write_back)
444 transfer = "t"; 444 transfer = "t";
445 445
446 return StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u", 446 return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u",
447 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset); 447 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset);
448 } 448 }
449 } 449 }
@@ -457,16 +457,16 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn)
457 if (is_pre) { 457 if (is_pre) {
458 if (shift_amount == 0) { 458 if (shift_amount == 0) {
459 if (shift_type == 0) { 459 if (shift_type == 0) {
460 return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", 460 return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s",
461 opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); 461 opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang);
462 } 462 }
463 if (shift_type == 3) { 463 if (shift_type == 3) {
464 return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", 464 return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s",
465 opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); 465 opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang);
466 } 466 }
467 shift_amount = 32; 467 shift_amount = 32;
468 } 468 }
469 return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", 469 return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s",
470 opname, cond_to_str(cond), byte, rd, rn, minus, rm, 470 opname, cond_to_str(cond), byte, rd, rn, minus, rm,
471 shift_name, shift_amount, bang); 471 shift_name, shift_amount, bang);
472 } 472 }
@@ -477,17 +477,17 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn)
477 477
478 if (shift_amount == 0) { 478 if (shift_amount == 0) {
479 if (shift_type == 0) { 479 if (shift_type == 0) {
480 return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d", 480 return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d",
481 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); 481 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm);
482 } 482 }
483 if (shift_type == 3) { 483 if (shift_type == 3) {
484 return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX", 484 return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX",
485 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); 485 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm);
486 } 486 }
487 shift_amount = 32; 487 shift_amount = 32;
488 } 488 }
489 489
490 return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", 490 return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u",
491 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm, 491 opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm,
492 shift_name, shift_amount); 492 shift_name, shift_amount);
493} 493}
@@ -528,22 +528,22 @@ std::string ARM_Disasm::DisassembleMemHalf(uint32_t insn)
528 if (is_immed) { 528 if (is_immed) {
529 if (is_pre) { 529 if (is_pre) {
530 if (offset == 0) { 530 if (offset == 0) {
531 return StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); 531 return Common::StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn);
532 } else { 532 } else {
533 return StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s", 533 return Common::StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s",
534 opname, cond_to_str(cond), rd, rn, minus, offset, bang); 534 opname, cond_to_str(cond), rd, rn, minus, offset, bang);
535 } 535 }
536 } else { 536 } else {
537 return StringFromFormat("%s%sh\tr%d, [r%d], #%s%u", 537 return Common::StringFromFormat("%s%sh\tr%d, [r%d], #%s%u",
538 opname, cond_to_str(cond), rd, rn, minus, offset); 538 opname, cond_to_str(cond), rd, rn, minus, offset);
539 } 539 }
540 } 540 }
541 541
542 if (is_pre) { 542 if (is_pre) {
543 return StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s", 543 return Common::StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s",
544 opname, cond_to_str(cond), rd, rn, minus, rm, bang); 544 opname, cond_to_str(cond), rd, rn, minus, rm, bang);
545 } else { 545 } else {
546 return StringFromFormat("%s%sh\tr%d, [r%d], %sr%d", 546 return Common::StringFromFormat("%s%sh\tr%d, [r%d], %sr%d",
547 opname, cond_to_str(cond), rd, rn, minus, rm); 547 opname, cond_to_str(cond), rd, rn, minus, rm);
548 } 548 }
549} 549}
@@ -558,7 +558,7 @@ std::string ARM_Disasm::DisassembleMCR(Opcode opcode, uint32_t insn)
558 uint8_t crm = insn & 0xf; 558 uint8_t crm = insn & 0xf;
559 559
560 const char *opname = opcode_names[opcode]; 560 const char *opname = opcode_names[opcode];
561 return StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", 561 return Common::StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}",
562 opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2); 562 opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2);
563} 563}
564 564
@@ -572,7 +572,7 @@ std::string ARM_Disasm::DisassembleMLA(Opcode opcode, uint32_t insn)
572 uint8_t bit_s = (insn >> 20) & 1; 572 uint8_t bit_s = (insn >> 20) & 1;
573 573
574 const char *opname = opcode_names[opcode]; 574 const char *opname = opcode_names[opcode];
575 return StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", 575 return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d",
576 opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn); 576 opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn);
577} 577}
578 578
@@ -586,7 +586,7 @@ std::string ARM_Disasm::DisassembleUMLAL(Opcode opcode, uint32_t insn)
586 uint8_t bit_s = (insn >> 20) & 1; 586 uint8_t bit_s = (insn >> 20) & 1;
587 587
588 const char *opname = opcode_names[opcode]; 588 const char *opname = opcode_names[opcode];
589 return StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", 589 return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d",
590 opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs); 590 opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs);
591} 591}
592 592
@@ -599,7 +599,7 @@ std::string ARM_Disasm::DisassembleMUL(Opcode opcode, uint32_t insn)
599 uint8_t bit_s = (insn >> 20) & 1; 599 uint8_t bit_s = (insn >> 20) & 1;
600 600
601 const char *opname = opcode_names[opcode]; 601 const char *opname = opcode_names[opcode];
602 return StringFromFormat("%s%s%s\tr%d, r%d, r%d", 602 return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d",
603 opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs); 603 opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs);
604} 604}
605 605
@@ -609,7 +609,7 @@ std::string ARM_Disasm::DisassembleMRS(uint32_t insn)
609 uint8_t rd = (insn >> 12) & 0xf; 609 uint8_t rd = (insn >> 12) & 0xf;
610 uint8_t ps = (insn >> 22) & 1; 610 uint8_t ps = (insn >> 22) & 1;
611 611
612 return StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); 612 return Common::StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr");
613} 613}
614 614
615std::string ARM_Disasm::DisassembleMSR(uint32_t insn) 615std::string ARM_Disasm::DisassembleMSR(uint32_t insn)
@@ -636,13 +636,13 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn)
636 uint8_t rotate = (insn >> 8) & 0xf; 636 uint8_t rotate = (insn >> 8) & 0xf;
637 uint8_t rotate2 = rotate << 1; 637 uint8_t rotate2 = rotate << 1;
638 uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); 638 uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2));
639 return StringFromFormat("msr%s\t%s_%s, #0x%x", 639 return Common::StringFromFormat("msr%s\t%s_%s, #0x%x",
640 cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val); 640 cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val);
641 } 641 }
642 642
643 uint8_t rm = insn & 0xf; 643 uint8_t rm = insn & 0xf;
644 644
645 return StringFromFormat("msr%s\t%s_%s, r%d", 645 return Common::StringFromFormat("msr%s\t%s_%s, r%d",
646 cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); 646 cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm);
647} 647}
648 648
@@ -658,14 +658,14 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn)
658 658
659 if (is_reg) { 659 if (is_reg) {
660 uint8_t rm = insn & 0xf; 660 uint8_t rm = insn & 0xf;
661 return StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm); 661 return Common::StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm);
662 } 662 }
663 663
664 uint16_t offset = insn & 0xfff; 664 uint16_t offset = insn & 0xfff;
665 if (offset == 0) { 665 if (offset == 0) {
666 return StringFromFormat("pld\t[r%d]", rn); 666 return Common::StringFromFormat("pld\t[r%d]", rn);
667 } else { 667 } else {
668 return StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset); 668 return Common::StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset);
669 } 669 }
670} 670}
671 671
@@ -674,7 +674,7 @@ std::string ARM_Disasm::DisassembleSWI(uint32_t insn)
674 uint8_t cond = (insn >> 28) & 0xf; 674 uint8_t cond = (insn >> 28) & 0xf;
675 uint32_t sysnum = insn & 0x00ffffff; 675 uint32_t sysnum = insn & 0x00ffffff;
676 676
677 return StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum); 677 return Common::StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum);
678} 678}
679 679
680std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) 680std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn)
@@ -685,7 +685,7 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn)
685 uint8_t rm = insn & 0xf; 685 uint8_t rm = insn & 0xf;
686 686
687 const char *opname = opcode_names[opcode]; 687 const char *opname = opcode_names[opcode];
688 return StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); 688 return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn);
689} 689}
690 690
691Opcode ARM_Disasm::Decode(uint32_t insn) { 691Opcode 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 @@
6#include <vector> 6#include <vector>
7 7
8#include "common/symbols.h" 8#include "common/symbols.h"
9#include "common/common_types.h"
10#include "common/file_util.h" 9#include "common/file_util.h"
11 10
12#include "core/arm/disassembler/load_symbol_map.h" 11#include "core/arm/disassembler/load_symbol_map.h"
@@ -19,7 +18,7 @@ void LoadSymbolMap(std::string filename) {
19 std::ifstream infile(filename); 18 std::ifstream infile(filename);
20 19
21 std::string address_str, function_name, line; 20 std::string address_str, function_name, line;
22 u32 size, address; 21 u32 size;
23 22
24 while (std::getline(infile, line)) { 23 while (std::getline(infile, line)) {
25 std::istringstream iss(line); 24 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "core/arm/skyeye_common/armcpu.h"
6#include "core/arm/skyeye_common/armemu.h"
7#include "core/arm/skyeye_common/vfp/vfp.h"
8
9#include "core/arm/dyncom/arm_dyncom.h"
10#include "core/arm/dyncom/arm_dyncom_interpreter.h"
11
12const static cpu_config_t s_arm11_cpu_info = {
13 "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE
14};
15
16ARM_DynCom::ARM_DynCom() : ticks(0) {
17 state = std::unique_ptr<ARMul_State>(new ARMul_State);
18
19 ARMul_EmulateInit();
20 memset(state.get(), 0, sizeof(ARMul_State));
21
22 ARMul_NewState((ARMul_State*)state.get());
23
24 state->abort_model = 0;
25 state->cpu = (cpu_config_t*)&s_arm11_cpu_info;
26 state->bigendSig = LOW;
27
28 ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
29 state->lateabtSig = LOW;
30
31 // Reset the core to initial state
32 ARMul_CoProInit(state.get());
33 ARMul_Reset(state.get());
34 state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext
35 state->Emulate = 3;
36
37 state->pc = state->Reg[15] = 0x00000000;
38 state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
39 state->servaddr = 0xFFFF0000;
40 state->NirqSig = HIGH;
41
42 VFPInit(state.get()); // Initialize the VFP
43
44 ARMul_EmulateInit();
45}
46
47ARM_DynCom::~ARM_DynCom() {
48}
49
50/**
51 * Set the Program Counter to an address
52 * @param addr Address to set PC to
53 */
54void ARM_DynCom::SetPC(u32 pc) {
55 state->pc = state->Reg[15] = pc;
56}
57
58/*
59 * Get the current Program Counter
60 * @return Returns current PC
61 */
62u32 ARM_DynCom::GetPC() const {
63 return state->Reg[15];
64}
65
66/**
67 * Get an ARM register
68 * @param index Register index (0-15)
69 * @return Returns the value in the register
70 */
71u32 ARM_DynCom::GetReg(int index) const {
72 return state->Reg[index];
73}
74
75/**
76 * Set an ARM register
77 * @param index Register index (0-15)
78 * @param value Value to set register to
79 */
80void ARM_DynCom::SetReg(int index, u32 value) {
81 state->Reg[index] = value;
82}
83
84/**
85 * Get the current CPSR register
86 * @return Returns the value of the CPSR register
87 */
88u32 ARM_DynCom::GetCPSR() const {
89 return state->Cpsr;
90}
91
92/**
93 * Set the current CPSR register
94 * @param cpsr Value to set CPSR to
95 */
96void ARM_DynCom::SetCPSR(u32 cpsr) {
97 state->Cpsr = cpsr;
98}
99
100/**
101 * Returns the number of clock ticks since the last reset
102 * @return Returns number of clock ticks
103 */
104u64 ARM_DynCom::GetTicks() const {
105 return ticks;
106}
107
108/**
109 * Executes the given number of instructions
110 * @param num_instructions Number of instructions to executes
111 */
112void ARM_DynCom::ExecuteInstructions(int num_instructions) {
113 state->NumInstrsToExecute = num_instructions;
114
115 // Dyncom only breaks on instruction dispatch. This only happens on every instruction when
116 // executing one instruction at a time. Otherwise, if a block is being executed, more
117 // instructions may actually be executed than specified.
118 ticks += InterpreterMainLoop(state.get());
119}
120
121/**
122 * Saves the current CPU context
123 * @param ctx Thread context to save
124 * @todo Do we need to save Reg[15] and NextInstr?
125 */
126void ARM_DynCom::SaveContext(ThreadContext& ctx) {
127 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
128 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
129
130 ctx.sp = state->Reg[13];
131 ctx.lr = state->Reg[14];
132 ctx.pc = state->Reg[15];
133 ctx.cpsr = state->Cpsr;
134
135 ctx.fpscr = state->VFP[1];
136 ctx.fpexc = state->VFP[2];
137
138 ctx.reg_15 = state->Reg[15];
139 ctx.mode = state->NextInstr;
140}
141
142/**
143 * Loads a CPU context
144 * @param ctx Thread context to load
145 * @param Do we need to load Reg[15] and NextInstr?
146 */
147void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
148 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
149 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
150
151 state->Reg[13] = ctx.sp;
152 state->Reg[14] = ctx.lr;
153 state->pc = ctx.pc;
154 state->Cpsr = ctx.cpsr;
155
156 state->VFP[1] = ctx.fpscr;
157 state->VFP[2] = ctx.fpexc;
158
159 state->Reg[15] = ctx.reg_15;
160 state->NextInstr = ctx.mode;
161}
162
163/// Prepare core for thread reschedule (if needed to correctly handle state)
164void ARM_DynCom::PrepareReschedule() {
165 state->NumInstrsToExecute = 0;
166}
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "common/common_types.h"
10
11#include "core/arm/arm_interface.h"
12#include "core/arm/skyeye_common/armdefs.h"
13
14class ARM_DynCom final : virtual public ARM_Interface {
15public:
16
17 ARM_DynCom();
18 ~ARM_DynCom();
19
20 /**
21 * Set the Program Counter to an address
22 * @param addr Address to set PC to
23 */
24 void SetPC(u32 pc) override;
25
26 /*
27 * Get the current Program Counter
28 * @return Returns current PC
29 */
30 u32 GetPC() const;
31
32 /**
33 * Get an ARM register
34 * @param index Register index (0-15)
35 * @return Returns the value in the register
36 */
37 u32 GetReg(int index) const;
38
39 /**
40 * Set an ARM register
41 * @param index Register index (0-15)
42 * @param value Value to set register to
43 */
44 void SetReg(int index, u32 value) override;
45
46 /**
47 * Get the current CPSR register
48 * @return Returns the value of the CPSR register
49 */
50 u32 GetCPSR() const;
51
52 /**
53 * Set the current CPSR register
54 * @param cpsr Value to set CPSR to
55 */
56 void SetCPSR(u32 cpsr) override;
57
58 /**
59 * Returns the number of clock ticks since the last reset
60 * @return Returns number of clock ticks
61 */
62 u64 GetTicks() const;
63
64 /**
65 * Saves the current CPU context
66 * @param ctx Thread context to save
67 */
68 void SaveContext(ThreadContext& ctx) override;
69
70 /**
71 * Loads a CPU context
72 * @param ctx Thread context to load
73 */
74 void LoadContext(const ThreadContext& ctx) override;
75
76 /// Prepare core for thread reschedule (if needed to correctly handle state)
77 void PrepareReschedule() override;
78
79 /**
80 * Executes the given number of instructions
81 * @param num_instructions Number of instructions to executes
82 */
83 void ExecuteInstructions(int num_instructions) override;
84
85private:
86
87 std::unique_ptr<ARMul_State> state;
88 u64 ticks;
89
90};
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 @@
1/* Copyright (C)
2* 2012 - Michael.Kang blackfin.kang@gmail.com
3* This program is free software; you can redistribute it and/or
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18/**
19* @file arm_dyncom_dec.cpp
20* @brief Some common utility for arm decoder
21* @author Michael.Kang blackfin.kang@gmail.com
22* @version 7849
23* @date 2012-03-15
24*/
25
26#include "core/arm/skyeye_common/arm_regformat.h"
27#include "core/arm/skyeye_common/armdefs.h"
28#include "core/arm/dyncom/arm_dyncom_dec.h"
29
30const ISEITEM arm_instruction[] = {
31 #define VFP_DECODE
32 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
33 #undef VFP_DECODE
34 {"srs" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005},
35 {"rfe" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a},
36 {"bkpt" , 2 , 3 , 20, 31, 0x00000e12, 4, 7, 0x00000007},
37 {"blx" , 1 , 3 , 25, 31, 0x0000007d},
38 {"cps" , 3 , 6 , 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000},
39 {"pld" , 4 , 4 , 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f},
40 {"setend" , 2 , 6 , 16, 31, 0x0000f101, 4, 7, 0x00000000},
41 {"clrex" , 1 , 6 , 0, 31, 0xf57ff01f},
42 {"rev16" , 2 , 6 , 16, 27, 0x000006bf, 4, 11, 0x000000fb},
43 {"usad8" , 3 , 6 , 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001},
44 {"sxtb" , 2 , 6 , 16, 27, 0x000006af, 4, 7, 0x00000007},
45 {"uxtb" , 2 , 6 , 16, 27, 0x000006ef, 4, 7, 0x00000007},
46 {"sxth" , 2 , 6 , 16, 27, 0x000006bf, 4, 7, 0x00000007},
47 {"sxtb16" , 2 , 6 , 16, 27, 0x0000068f, 4, 7, 0x00000007},
48 {"uxth" , 2 , 6 , 16, 27, 0x000006ff, 4, 7, 0x00000007},
49 {"uxtb16" , 2 , 6 , 16, 27, 0x000006cf, 4, 7, 0x00000007},
50 {"cpy" , 2 , 6 , 20, 27, 0x0000001a, 4, 11, 0x00000000},
51 {"uxtab" , 2 , 6 , 20, 27, 0x0000006e, 4, 9, 0x00000007},
52 {"ssub8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x0000000f},
53 {"shsub8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x0000000f},
54 {"ssubaddx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000005},
55 {"strex" , 2 , 6 , 20, 27, 0x00000018, 4, 7, 0x00000009},
56 {"strexb" , 2 , 7 , 20, 27, 0x0000001c, 4, 7, 0x00000009},
57 {"swp" , 2 , 0 , 20, 27, 0x00000010, 4, 7, 0x00000009},
58 {"swpb" , 2 , 0 , 20, 27, 0x00000014, 4, 7, 0x00000009},
59 {"ssub16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000007},
60 {"ssat16" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000003},
61 {"shsubaddx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000005},
62 {"qsubaddx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000005},
63 {"shaddsubx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000003},
64 {"shadd8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000009},
65 {"shadd16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000001},
66 {"sel" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x0000000b},
67 {"saddsubx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000003},
68 {"sadd8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000009},
69 {"sadd16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000001},
70 {"shsub16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000007},
71 {"umaal" , 2 , 6 , 20, 27, 0x00000004, 4, 7, 0x00000009},
72 {"uxtab16" , 2 , 6 , 20, 27, 0x0000006c, 4, 7, 0x00000007},
73 {"usubaddx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000005},
74 {"usub8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x0000000f},
75 {"usub16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000007},
76 {"usat16" , 2 , 6 , 20, 27, 0x0000006e, 4, 7, 0x00000003},
77 {"usada8" , 2 , 6 , 20, 27, 0x00000078, 4, 7, 0x00000001},
78 {"uqsubaddx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000005},
79 {"uqsub8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x0000000f},
80 {"uqsub16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000007},
81 {"uqaddsubx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000003},
82 {"uqadd8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000009},
83 {"uqadd16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000001},
84 {"sxtab" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000007},
85 {"uhsubaddx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000005},
86 {"uhsub8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x0000000f},
87 {"uhsub16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000007},
88 {"uhaddsubx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000003},
89 {"uhadd8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000009},
90 {"uhadd16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000001},
91 {"uaddsubx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000003},
92 {"uadd8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000009},
93 {"uadd16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000001},
94 {"sxtah" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000007},
95 {"sxtab16" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x00000007},
96 {"qadd8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000009},
97 {"bxj" , 2 , 5 , 20, 27, 0x00000012, 4, 7, 0x00000002},
98 {"clz" , 2 , 3 , 20, 27, 0x00000016, 4, 7, 0x00000001},
99 {"uxtah" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x00000007},
100 {"bx" , 2 , 2 , 20, 27, 0x00000012, 4, 7, 0x00000001},
101 {"rev" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000003},
102 {"blx" , 2 , 3 , 20, 27, 0x00000012, 4, 7, 0x00000003},
103 {"revsh" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x0000000b},
104 {"qadd" , 2 , 4 , 20, 27, 0x00000010, 4, 7, 0x00000005},
105 {"qadd16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000001},
106 {"qaddsubx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000003},
107 {"ldrex" , 2 , 0 , 20, 27, 0x00000019, 4, 7, 0x00000009},
108 {"qdadd" , 2 , 4 , 20, 27, 0x00000014, 4, 7, 0x00000005},
109 {"qdsub" , 2 , 4 , 20, 27, 0x00000016, 4, 7, 0x00000005},
110 {"qsub" , 2 , 4 , 20, 27, 0x00000012, 4, 7, 0x00000005},
111 {"ldrexb" , 2 , 7 , 20, 27, 0x0000001d, 4, 7, 0x00000009},
112 {"qsub8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x0000000f},
113 {"qsub16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000007},
114 {"smuad" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001},
115 {"smmul" , 4 , 6 , 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001},
116 {"smusd" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001},
117 {"smlsd" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001},
118 {"smlsld" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001},
119 {"smmla" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001},
120 {"smmls" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001},
121 {"smlald" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001},
122 {"smlad" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001},
123 {"smlaw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000},
124 {"smulw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002},
125 {"pkhtb" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000005},
126 {"pkhbt" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000001},
127 {"smul" , 3 , 4 , 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000},
128 {"smlalxy" , 3 , 4 , 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000},
129// {"smlal" , 2 , 4 , 21, 27, 0x00000007, 4, 7, 0x00000009},
130 {"smla" , 3 , 4 , 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000},
131 {"mcrr" , 1 , 6 , 20, 27, 0x000000c4},
132 {"mrrc" , 1 , 6 , 20, 27, 0x000000c5},
133 {"cmp" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000015},
134 {"tst" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000011},
135 {"teq" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000013},
136 {"cmn" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000017},
137 {"smull" , 2 , 0 , 21, 27, 0x00000006, 4, 7, 0x00000009},
138 {"umull" , 2 , 0 , 21, 27, 0x00000004, 4, 7, 0x00000009},
139 {"umlal" , 2 , 0 , 21, 27, 0x00000005, 4, 7, 0x00000009},
140 {"smlal" , 2 , 0 , 21, 27, 0x00000007, 4, 7, 0x00000009},
141 {"mul" , 2 , 0 , 21, 27, 0x00000000, 4, 7, 0x00000009},
142 {"mla" , 2 , 0 , 21, 27, 0x00000001, 4, 7, 0x00000009},
143 {"ssat" , 2 , 6 , 21, 27, 0x00000035, 4, 5, 0x00000001},
144 {"usat" , 2 , 6 , 21, 27, 0x00000037, 4, 5, 0x00000001},
145 {"mrs" , 4 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000},
146 {"msr" , 3 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000},
147 {"and" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000000},
148 {"bic" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000e},
149 {"ldm" , 3 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000},
150 {"eor" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000001},
151 {"add" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000004},
152 {"rsb" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000003},
153 {"rsc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000007},
154 {"sbc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000006},
155 {"adc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000005},
156 {"sub" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000002},
157 {"orr" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000c},
158 {"mvn" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000f},
159 {"mov" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000d},
160 {"stm" , 2 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000004},
161 {"ldm" , 4 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001},
162 {"ldrsh" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f},
163 {"stm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000},
164 {"ldm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001},
165 {"ldrsb" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d},
166 {"strd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f},
167 {"ldrh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b},
168 {"strh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b},
169 {"ldrd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d},
170 {"strt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002},
171 {"strbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006},
172 {"ldrbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007},
173 {"ldrt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003},
174 {"mrc" , 3 , 6 , 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001},
175 {"mcr" , 3 , 0 , 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001},
176 {"msr" , 2 , 0 , 23, 27, 0x00000006, 20, 21, 0x00000002},
177 {"ldrb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001},
178 {"strb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000},
179 {"ldr" , 4 , 0 , 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001},
180 {"ldrcond" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001},
181 {"str" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000},
182 {"cdp" , 2 , 0 , 24, 27, 0x0000000e, 4, 4, 0x00000000},
183 {"stc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000000},
184 {"ldc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000001},
185 {"swi" , 1 , 0 , 24, 27, 0x0000000f},
186 {"bbl" , 1 , 0 , 25, 27, 0x00000005},
187};
188
189const ISEITEM arm_exclusion_code[] = {
190 #define VFP_DECODE_EXCLUSION
191 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
192 #undef VFP_DECODE_EXCLUSION
193 {"srs" , 0 , 6 , 0},
194 {"rfe" , 0 , 6 , 0},
195 {"bkpt" , 0 , 3 , 0},
196 {"blx" , 0 , 3 , 0},
197 {"cps" , 0 , 6 , 0},
198 {"pld" , 0 , 4 , 0},
199 {"setend" , 0 , 6 , 0},
200 {"clrex" , 0 , 6 , 0},
201 {"rev16" , 0 , 6 , 0},
202 {"usad8" , 0 , 6 , 0},
203 {"sxtb" , 0 , 6 , 0},
204 {"uxtb" , 0 , 6 , 0},
205 {"sxth" , 0 , 6 , 0},
206 {"sxtb16" , 0 , 6 , 0},
207 {"uxth" , 0 , 6 , 0},
208 {"uxtb16" , 0 , 6 , 0},
209 {"cpy" , 0 , 6 , 0},
210 {"uxtab" , 0 , 6 , 0},
211 {"ssub8" , 0 , 6 , 0},
212 {"shsub8" , 0 , 6 , 0},
213 {"ssubaddx" , 0 , 6 , 0},
214 {"strex" , 0 , 6 , 0},
215 {"strexb" , 0 , 7 , 0},
216 {"swp" , 0 , 0 , 0},
217 {"swpb" , 0 , 0 , 0},
218 {"ssub16" , 0 , 6 , 0},
219 {"ssat16" , 0 , 6 , 0},
220 {"shsubaddx" , 0 , 6 , 0},
221 {"qsubaddx" , 0 , 6 , 0},
222 {"shaddsubx" , 0 , 6 , 0},
223 {"shadd8" , 0 , 6 , 0},
224 {"shadd16" , 0 , 6 , 0},
225 {"sel" , 0 , 6 , 0},
226 {"saddsubx" , 0 , 6 , 0},
227 {"sadd8" , 0 , 6 , 0},
228 {"sadd16" , 0 , 6 , 0},
229 {"shsub16" , 0 , 6 , 0},
230 {"umaal" , 0 , 6 , 0},
231 {"uxtab16" , 0 , 6 , 0},
232 {"usubaddx" , 0 , 6 , 0},
233 {"usub8" , 0 , 6 , 0},
234 {"usub16" , 0 , 6 , 0},
235 {"usat16" , 0 , 6 , 0},
236 {"usada8" , 0 , 6 , 0},
237 {"uqsubaddx" , 0 , 6 , 0},
238 {"uqsub8" , 0 , 6 , 0},
239 {"uqsub16" , 0 , 6 , 0},
240 {"uqaddsubx" , 0 , 6 , 0},
241 {"uqadd8" , 0 , 6 , 0},
242 {"uqadd16" , 0 , 6 , 0},
243 {"sxtab" , 0 , 6 , 0},
244 {"uhsubaddx" , 0 , 6 , 0},
245 {"uhsub8" , 0 , 6 , 0},
246 {"uhsub16" , 0 , 6 , 0},
247 {"uhaddsubx" , 0 , 6 , 0},
248 {"uhadd8" , 0 , 6 , 0},
249 {"uhadd16" , 0 , 6 , 0},
250 {"uaddsubx" , 0 , 6 , 0},
251 {"uadd8" , 0 , 6 , 0},
252 {"uadd16" , 0 , 6 , 0},
253 {"sxtah" , 0 , 6 , 0},
254 {"sxtab16" , 0 , 6 , 0},
255 {"qadd8" , 0 , 6 , 0},
256 {"bxj" , 0 , 5 , 0},
257 {"clz" , 0 , 3 , 0},
258 {"uxtah" , 0 , 6 , 0},
259 {"bx" , 0 , 2 , 0},
260 {"rev" , 0 , 6 , 0},
261 {"blx" , 0 , 3 , 0},
262 {"revsh" , 0 , 6 , 0},
263 {"qadd" , 0 , 4 , 0},
264 {"qadd16" , 0 , 6 , 0},
265 {"qaddsubx" , 0 , 6 , 0},
266 {"ldrex" , 0 , 0 , 0},
267 {"qdadd" , 0 , 4 , 0},
268 {"qdsub" , 0 , 4 , 0},
269 {"qsub" , 0 , 4 , 0},
270 {"ldrexb" , 0 , 7 , 0},
271 {"qsub8" , 0 , 6 , 0},
272 {"qsub16" , 0 , 6 , 0},
273 {"smuad" , 0 , 6 , 0},
274 {"smmul" , 0 , 6 , 0},
275 {"smusd" , 0 , 6 , 0},
276 {"smlsd" , 0 , 6 , 0},
277 {"smlsld" , 0 , 6 , 0},
278 {"smmla" , 0 , 6 , 0},
279 {"smmls" , 0 , 6 , 0},
280 {"smlald" , 0 , 6 , 0},
281 {"smlad" , 0 , 6 , 0},
282 {"smlaw" , 0 , 4 , 0},
283 {"smulw" , 0 , 4 , 0},
284 {"pkhtb" , 0 , 6 , 0},
285 {"pkhbt" , 0 , 6 , 0},
286 {"smul" , 0 , 4 , 0},
287 {"smlal" , 0 , 4 , 0},
288 {"smla" , 0 , 4 , 0},
289 {"mcrr" , 0 , 6 , 0},
290 {"mrrc" , 0 , 6 , 0},
291 {"cmp" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
292 {"tst" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
293 {"teq" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
294 {"cmn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
295 {"smull" , 0 , 0 , 0},
296 {"umull" , 0 , 0 , 0},
297 {"umlal" , 0 , 0 , 0},
298 {"smlal" , 0 , 0 , 0},
299 {"mul" , 0 , 0 , 0},
300 {"mla" , 0 , 0 , 0},
301 {"ssat" , 0 , 6 , 0},
302 {"usat" , 0 , 6 , 0},
303 {"mrs" , 0 , 0 , 0},
304 {"msr" , 0 , 0 , 0},
305 {"and" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
306 {"bic" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
307 {"ldm" , 0 , 0 , 0},
308 {"eor" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
309 {"add" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
310 {"rsb" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
311 {"rsc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
312 {"sbc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
313 {"adc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
314 {"sub" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
315 {"orr" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
316 {"mvn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
317 {"mov" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000},
318 {"stm" , 0 , 0 , 0},
319 {"ldm" , 0 , 0 , 0},
320 {"ldrsh" , 0 , 2 , 0},
321 {"stm" , 0 , 0 , 0},
322 {"ldm" , 0 , 0 , 0},
323 {"ldrsb" , 0 , 2 , 0},
324 {"strd" , 0 , 4 , 0},
325 {"ldrh" , 0 , 0 , 0},
326 {"strh" , 0 , 0 , 0},
327 {"ldrd" , 0 , 4 , 0},
328 {"strt" , 0 , 0 , 0},
329 {"strbt" , 0 , 0 , 0},
330 {"ldrbt" , 0 , 0 , 0},
331 {"ldrt" , 0 , 0 , 0},
332 {"mrc" , 0 , 6 , 0},
333 {"mcr" , 0 , 0 , 0},
334 {"msr" , 0 , 0 , 0},
335 {"ldrb" , 0 , 0 , 0},
336 {"strb" , 0 , 0 , 0},
337 {"ldr" , 0 , 0 , 0},
338 {"ldrcond" , 1 , 0 , 28, 31, 0x0000000e},
339 {"str" , 0 , 0 , 0},
340 {"cdp" , 0 , 0 , 0},
341 {"stc" , 0 , 0 , 0},
342 {"ldc" , 0 , 0 , 0},
343 {"swi" , 0 , 0 , 0},
344 {"bbl" , 0 , 0 , 0},
345 {"bl_1_thumb", 0, INVALID, 0},/* should be table[-4] */
346 {"bl_2_thumb", 0, INVALID, 0}, /* should be located at the end of the table[-3] */
347 {"blx_1_thumb", 0, INVALID, 0}, /* should be located at table[-2] */
348 {"invalid", 0, INVALID, 0}
349};
350
351int decode_arm_instr(uint32_t instr, int32_t *idx)
352{
353 int n = 0;
354 int base = 0;
355 int ret = DECODE_FAILURE;
356 int i = 0;
357 int instr_slots = sizeof(arm_instruction)/sizeof(ISEITEM);
358 for (i = 0; i < instr_slots; i++)
359 {
360// ret = DECODE_SUCCESS;
361 n = arm_instruction[i].attribute_value;
362 base = 0;
363 while (n) {
364 if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) {
365 /* clrex */
366 if (instr != arm_instruction[i].content[base + 2]) {
367 break;
368 }
369 } else if (BITS(arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) {
370 break;
371 }
372 base += 3;
373 n --;
374 }
375 //All conditions is satisfied.
376 if (n == 0)
377 ret = DECODE_SUCCESS;
378
379 if (ret == DECODE_SUCCESS) {
380 n = arm_exclusion_code[i].attribute_value;
381 if (n != 0) {
382 base = 0;
383 while (n) {
384 if (BITS(arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) {
385 break; }
386 base += 3;
387 n --;
388 }
389 //All conditions is satisfied.
390 if (n == 0)
391 ret = DECODE_FAILURE;
392 }
393 }
394
395 if (ret == DECODE_SUCCESS) {
396 *idx = i;
397 return ret;
398 }
399 }
400 return ret;
401}
402
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 @@
1/* Copyright (C)
2* 2012 - Michael.Kang blackfin.kang@gmail.com
3* This program is free software; you can redistribute it and/or
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18
19/**
20* @file arm_dyncom_dec.h
21* @brief Some common utility for arm instruction decoder
22* @author Michael.Kang blackfin.kang@gmail.com
23* @version 7849
24* @date 2012-03-15
25*/
26
27#ifndef __ARM_DYNCOM_DEC__
28#define __ARM_DYNCOM_DEC__
29
30#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1))
31#define BIT(n) ((instr >> (n)) & 1)
32#define BAD do{printf("meet BAD at %s, instr is %x\n", __FUNCTION__, instr ); /*exit(0);*/}while(0);
33#define ptr_N cpu->ptr_N
34#define ptr_Z cpu->ptr_Z
35#define ptr_C cpu->ptr_C
36#define ptr_V cpu->ptr_V
37#define ptr_I cpu->ptr_I
38#define ptr_T cpu->ptr_T
39#define ptr_CPSR cpu->ptr_gpr[16]
40
41/* for MUL instructions */
42/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */
43#define RDHi ((instr >> 16) & 0xF)
44/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */
45#define RDLo ((instr >> 12) & 0xF)
46/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */
47#define MUL_RD ((instr >> 16) & 0xF)
48/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */
49#define MUL_RN ((instr >> 12) & 0xF)
50/*xxxx xxxx xxxx xxxx xxxx 1111 xxxx xxxx */
51#define RS ((instr >> 8) & 0xF)
52
53/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */
54#define RD ((instr >> 12) & 0xF)
55/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */
56#define RN ((instr >> 16) & 0xF)
57/*xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 */
58#define RM (instr & 0xF)
59#define BIT(n) ((instr >> (n)) & 1)
60#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1))
61
62/* CP15 registers */
63#define OPCODE_1 BITS(21, 23)
64#define CRn BITS(16, 19)
65#define CRm BITS(0, 3)
66#define OPCODE_2 BITS(5, 7)
67
68/*xxxx xx1x xxxx xxxx xxxx xxxx xxxx xxxx */
69#define I BIT(25)
70/*xxxx xxxx xxx1 xxxx xxxx xxxx xxxx xxxx */
71#define S BIT(20)
72
73#define SHIFT BITS(5,6)
74#define SHIFT_IMM BITS(7,11)
75#define IMMH BITS(8,11)
76#define IMML BITS(0,3)
77
78#define LSPBIT BIT(24)
79#define LSUBIT BIT(23)
80#define LSBBIT BIT(22)
81#define LSWBIT BIT(21)
82#define LSLBIT BIT(20)
83#define LSSHBITS BITS(5,6)
84#define OFFSET12 BITS(0,11)
85#define SBIT BIT(20)
86#define DESTReg (BITS (12, 15))
87
88/* they are in unused state, give a corrent value when using */
89#define IS_V5E 0
90#define IS_V5 0
91#define IS_V6 0
92#define LHSReg 0
93
94/* temp define the using the pc reg need implement a flow */
95#define STORE_CHECK_RD_PC ADD(R(RD), CONST(INSTR_SIZE * 2))
96
97#define OPERAND operand(cpu,instr,bb,NULL)
98#define SCO_OPERAND(sco) operand(cpu,instr,bb,sco)
99#define BOPERAND boperand(instr)
100
101#define CHECK_RN_PC (RN==15? ADD(AND(R(RN), CONST(~0x1)), CONST(INSTR_SIZE * 2)):R(RN))
102#define CHECK_RN_PC_WA (RN==15? ADD(AND(R(RN), CONST(~0x3)), CONST(INSTR_SIZE * 2)):R(RN))
103
104#define GET_USER_MODE() (OR(ICMP_EQ(R(MODE_REG), CONST(USER32MODE)), ICMP_EQ(R(MODE_REG), CONST(SYSTEM32MODE))))
105
106int decode_arm_instr(uint32_t instr, int32_t *idx);
107
108enum DECODE_STATUS {
109 DECODE_SUCCESS,
110 DECODE_FAILURE
111};
112
113struct instruction_set_encoding_item {
114 const char *name;
115 int attribute_value;
116 int version;
117 u32 content[21];
118};
119
120typedef struct instruction_set_encoding_item ISEITEM;
121
122#define RECORD_WB(value, flag) {cpu->dyncom_engine->wb_value = value;cpu->dyncom_engine->wb_flag = flag;}
123#define INIT_WB(wb_value, wb_flag) RECORD_WB(wb_value, wb_flag)
124
125#define EXECUTE_WB(base_reg) {if(cpu->dyncom_engine->wb_flag) \
126 LET(base_reg, cpu->dyncom_engine->wb_value);}
127inline int get_reg_count(uint32_t instr){
128 int i = BITS(0,15);
129 int count = 0;
130 while(i){
131 if(i & 1)
132 count ++;
133 i = i >> 1;
134 }
135 return count;
136}
137
138enum ARMVER {
139 INVALID = 0,
140 ARMALL,
141 ARMV4,
142 ARMV4T,
143 ARMV5T,
144 ARMV5TE,
145 ARMV5TEJ,
146 ARMV6,
147 ARM1176JZF_S,
148 ARMVFP2,
149 ARMVFP3
150};
151
152//extern const INSTRACT arm_instruction_action[];
153extern const ISEITEM arm_instruction[];
154
155#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 @@
1/* Copyright (C)
2* 2012 - Michael.Kang blackfin.kang@gmail.com
3* This program is free software; you can redistribute it and/or
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18/**
19* @file arm_dyncom_interpreter.cpp
20* @brief The fast interpreter for arm
21* @author Michael.Kang blackfin.kang@gmail.com
22* @version 7849
23* @date 2012-03-15
24*/
25
26#define CITRA_IGNORE_EXIT(x)
27
28#include <algorithm>
29#include <map>
30#include <stdio.h>
31#include <assert.h>
32#include <cstdio>
33#include <vector>
34
35using namespace std;
36
37#include "core/arm/skyeye_common/armdefs.h"
38#include "core/arm/skyeye_common/armmmu.h"
39#include "arm_dyncom_thumb.h"
40#include "arm_dyncom_run.h"
41#include "core/arm/skyeye_common/vfp/vfp.h"
42/* shenoubang 2012-6-14 */
43#ifdef __WIN32__
44#include "bank_defs.h"
45#endif
46
47#include "core/mem_map.h"
48#include "core/hle/hle.h"
49
50enum {
51 COND = (1 << 0),
52 NON_BRANCH = (1 << 1),
53 DIRECT_BRANCH = (1 << 2),
54 INDIRECT_BRANCH = (1 << 3),
55 CALL = (1 << 4),
56 RET = (1 << 5),
57 END_OF_PAGE = (1 << 6),
58 THUMB = (1 << 7)
59};
60
61#define USER_MODE_OPT 1
62#define HYBRID_MODE 0 // Enable for JIT mode
63
64#define THRESHOLD 1000
65#define DURATION 500
66//#define PRINT_PROFILE_INFO
67
68#define CHECK_RS if(RS == 15) rs += 8
69#define CHECK_RM if(RM == 15) rm += 8
70
71//#define BITS(s, a, b) (((s) >> (a)) & ((1 << (1 + (b) - (a))) - 1))
72#undef BITS
73#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
74#define BIT(s, n) ((s >> (n)) & 1)
75#define RM BITS(sht_oper, 0, 3)
76#define RS BITS(sht_oper, 8, 11)
77
78#define glue(x, y) x ## y
79#define DPO(s) glue(DataProcessingOperands, s)
80#define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i))
81#define ROTATE_LEFT(n, i, l) ((n >> (l - i)) | (n << i))
82#define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32)
83#define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32)
84
85//#define rotr(x,n) ((((x)>>(n))&((1<<(sizeof(x) * 8)-1))|(x<<(sizeof(x)*8-n))))
86//#define rotl(x,n) ((((x)<<(n))&(-(1<<(n))))|(((x)>>(sizeof(x)*8-n))&((1<<(n))-1)))
87#define rotr(x,n) ( (x >> n) | ((x & ((1 << (n + 1)) - 1)) << (32 - n)) )
88
89extern void switch_mode(arm_core_t *core, uint32_t mode);
90//extern bool InAPrivilegedMode(arm_core_t *core);
91
92typedef arm_core_t arm_processor;
93typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper);
94
95/* exclusive memory access */
96static int exclusive_detect(ARMul_State* state, ARMword addr){
97 int i;
98 #if 0
99 for(i = 0; i < 128; i++){
100 if(state->exclusive_tag_array[i] == addr)
101 return 0;
102 }
103 #endif
104 if(state->exclusive_tag == addr)
105 return 0;
106 else
107 return -1;
108}
109
110static void add_exclusive_addr(ARMul_State* state, ARMword addr){
111 int i;
112 #if 0
113 for(i = 0; i < 128; i++){
114 if(state->exclusive_tag_array[i] == 0xffffffff){
115 state->exclusive_tag_array[i] = addr;
116 //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr);
117 return;
118 }
119 }
120 DEBUG_LOG(ARM11, "In %s ,can not monitor the addr, out of array\n", __FUNCTION__);
121 #endif
122 state->exclusive_tag = addr;
123 return;
124}
125
126static void remove_exclusive(ARMul_State* state, ARMword addr){
127 #if 0
128 int i;
129 for(i = 0; i < 128; i++){
130 if(state->exclusive_tag_array[i] == addr){
131 state->exclusive_tag_array[i] = 0xffffffff;
132 //DEBUG_LOG(ARM11, "In %s, remove addr 0x%x\n", __func__, addr);
133 return;
134 }
135 }
136 #endif
137 state->exclusive_tag = 0xFFFFFFFF;
138}
139
140
141unsigned int DPO(Immediate)(arm_processor *cpu, unsigned int sht_oper)
142{
143// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
144 unsigned int immed_8 = BITS(sht_oper, 0, 7);
145 unsigned int rotate_imm = BITS(sht_oper, 8, 11);
146// DEBUG_LOG(ARM11, "immed_8 is %x\n", immed_8);
147// DEBUG_LOG(ARM11, "rotate_imm is %x\n", rotate_imm);
148 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);//ROTATE_RIGHT_32(immed_8, rotate_imm * 2);
149// DEBUG_LOG(ARM11, "shifter_operand : %x\n", shifter_operand);
150 /* set c flag */
151 if (rotate_imm == 0)
152 cpu->shifter_carry_out = cpu->CFlag;
153 else
154 cpu->shifter_carry_out = BIT(shifter_operand, 31);
155 return shifter_operand;
156}
157
158unsigned int DPO(Register)(arm_processor *cpu, unsigned int sht_oper)
159{
160// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
161 unsigned int rm = CHECK_READ_REG15(cpu, RM);
162 //if (RM == 15) rm += 8;
163 unsigned int shifter_operand = rm;
164 cpu->shifter_carry_out = cpu->CFlag;
165 return shifter_operand;
166}
167
168unsigned int DPO(LogicalShiftLeftByImmediate)(arm_processor *cpu, unsigned int sht_oper)
169{
170// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
171 int shift_imm = BITS(sht_oper, 7, 11);
172 unsigned int rm = CHECK_READ_REG15(cpu, RM);
173 //if (RM == 15) rm += 8;
174 unsigned int shifter_operand;
175 if (shift_imm == 0) {
176 shifter_operand = rm;
177 cpu->shifter_carry_out = cpu->CFlag;
178 } else {
179 shifter_operand = rm << shift_imm;
180 cpu->shifter_carry_out = BIT(rm, 32 - shift_imm);
181 }
182 return shifter_operand;
183}
184
185unsigned int DPO(LogicalShiftLeftByRegister)(arm_processor *cpu, unsigned int sht_oper)
186{
187// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
188 int shifter_operand;
189 unsigned int rm = CHECK_READ_REG15(cpu, RM);
190 unsigned int rs = CHECK_READ_REG15(cpu, RS);
191 //if (RM == 15) rm += 8;
192 //if (RS == 15) rs += 8;
193 if (BITS(rs, 0, 7) == 0) {
194 shifter_operand = rm;
195 cpu->shifter_carry_out = cpu->CFlag;
196 } else if (BITS(rs, 0, 7) < 32) {
197 shifter_operand = rm << BITS(rs, 0, 7);
198 cpu->shifter_carry_out = BIT(rm, 32 - BITS(rs, 0, 7));
199 } else if (BITS(rs, 0, 7) == 32) {
200 shifter_operand = 0;
201 cpu->shifter_carry_out = BIT(rm, 0);
202 } else {
203 shifter_operand = 0;
204 cpu->shifter_carry_out = 0;
205 }
206 return shifter_operand;
207}
208
209unsigned int DPO(LogicalShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
210{
211// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
212 //unsigned int rm = cpu->Reg[RM];
213 unsigned int rm = CHECK_READ_REG15(cpu, RM);
214 //if (RM == 15) rm += 8;
215 unsigned int shifter_operand;
216 int shift_imm = BITS(sht_oper, 7, 11);
217 if (shift_imm == 0) {
218 shifter_operand = 0;
219 cpu->shifter_carry_out = BIT(rm, 31);
220 } else {
221 shifter_operand = rm >> shift_imm;
222 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
223 }
224 return shifter_operand;
225}
226
227unsigned int DPO(LogicalShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
228{
229// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
230 unsigned int rs = CHECK_READ_REG15(cpu, RS);
231 unsigned int rm = CHECK_READ_REG15(cpu, RM);
232 //if (RS == 15) rs += 8;
233 //if (RM == 15) rm += 8;
234 unsigned int shifter_operand;
235 if (BITS(rs, 0, 7) == 0) {
236 shifter_operand = rm;
237 cpu->shifter_carry_out = cpu->CFlag;
238 } else if (BITS(rs, 0, 7) < 32) {
239 shifter_operand = rm >> BITS(rs, 0, 7);
240 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
241 } else if (BITS(rs, 0, 7) == 32) {
242 shifter_operand = 0;
243 cpu->shifter_carry_out = BIT(rm, 31);
244 } else {
245 shifter_operand = 0;
246 cpu->shifter_carry_out = 0;
247 }
248 return shifter_operand;
249}
250
251unsigned int DPO(ArithmeticShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
252{
253// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
254 //unsigned int rm = cpu->Reg[RM];
255 unsigned int rm = CHECK_READ_REG15(cpu, RM);
256 //if (RM == 15) rm += 8;
257 unsigned int shifter_operand;
258 int shift_imm = BITS(sht_oper, 7, 11);
259 if (shift_imm == 0) {
260 if (BIT(rm, 31)) {
261 shifter_operand = 0;
262 cpu->shifter_carry_out = BIT(rm, 31);
263 } else {
264 shifter_operand = 0xFFFFFFFF;
265 cpu->shifter_carry_out = BIT(rm, 31);
266 }
267 } else {
268 shifter_operand = static_cast<int>(rm) >> shift_imm;
269 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
270 }
271 return shifter_operand;
272}
273
274unsigned int DPO(ArithmeticShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
275{
276// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
277 //unsigned int rs = cpu->Reg[RS];
278 unsigned int rs = CHECK_READ_REG15(cpu, RS);
279 //unsigned int rm = cpu->Reg[RM];
280 unsigned int rm = CHECK_READ_REG15(cpu, RM);
281 //if (RS == 15) rs += 8;
282 //if (RM == 15) rm += 8;
283 unsigned int shifter_operand;
284 if (BITS(rs, 0, 7) == 0) {
285 shifter_operand = rm;
286 cpu->shifter_carry_out = cpu->CFlag;
287 } else if (BITS(rs, 0, 7) < 32) {
288 shifter_operand = static_cast<int>(rm) >> BITS(rs, 0, 7);
289 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
290 } else {
291 if (BIT(rm, 31) == 0) {
292 shifter_operand = 0;
293 } else
294 shifter_operand = 0xffffffff;
295 cpu->shifter_carry_out = BIT(rm, 31);
296 }
297 return shifter_operand;
298}
299
300unsigned int DPO(RotateRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
301{
302// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
303 unsigned int shifter_operand;
304 //unsigned int rm = cpu->Reg[RM];
305 unsigned int rm = CHECK_READ_REG15(cpu, RM);
306 //if (RM == 15) rm += 8;
307 int shift_imm = BITS(sht_oper, 7, 11);
308 if (shift_imm == 0) {
309 shifter_operand = (cpu->CFlag << 31) |
310 (rm >> 1);
311 cpu->shifter_carry_out = BIT(rm, 0);
312 } else {
313 shifter_operand = ROTATE_RIGHT_32(rm, shift_imm);
314 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
315 }
316 return shifter_operand;
317}
318
319unsigned int DPO(RotateRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
320{
321// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
322 unsigned int rm = CHECK_READ_REG15(cpu, RM);
323 //if (RM == 15) rm += 8;
324 unsigned int rs = CHECK_READ_REG15(cpu, RS);
325 //if (RS == 15) rs += 8;
326 unsigned int shifter_operand;
327 if (BITS(rs, 0, 7) == 0) {
328 shifter_operand = rm;
329 cpu->shifter_carry_out = cpu->CFlag;
330 } else if (BITS(rs, 0, 4) == 0) {
331 shifter_operand = rm;
332 cpu->shifter_carry_out = BIT(rm, 31);
333 } else {
334 shifter_operand = ROTATE_RIGHT_32(rm, BITS(rs, 0, 4));
335 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 4) - 1);
336 }
337 #if 0
338 if (cpu->icounter >= 20371544) {
339 DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
340 DEBUG_LOG(ARM11, "RM:%d\nRS:%d\n", RM, RS);
341 DEBUG_LOG(ARM11, "rm:0x%08x\nrs:0x%08x\n", cpu->Reg[RM], cpu->Reg[RS]);
342 }
343 #endif
344 return shifter_operand;
345}
346
347//typedef unsigned int (*get_addr_fp_t)(arm_processor *cpu);
348typedef struct _MiscImmeData {
349 unsigned int U;
350 unsigned int Rn;
351 unsigned int offset_8;
352} MiscLSData;
353
354typedef struct _MiscRegData {
355 unsigned int U;
356 unsigned int Rn;
357 unsigned int Rm;
358} MiscRegData;
359
360typedef struct _MiscImmePreIdx {
361 unsigned int offset_8;
362 unsigned int U;
363 unsigned int Rn;
364} MiscImmePreIdx;
365
366typedef struct _MiscRegPreIdx {
367 unsigned int U;
368 unsigned int Rn;
369 unsigned int Rm;
370} MiscRegPreIdx;
371
372typedef struct _MiscImmePstIdx {
373 unsigned int offset_8;
374 unsigned int U;
375 unsigned int Rn;
376} MIscImmePstIdx;
377
378typedef struct _MiscRegPstIdx {
379 unsigned int Rn;
380 unsigned int Rm;
381 unsigned int U;
382} MiscRegPstIdx;
383
384typedef struct _LSWordorUnsignedByte {
385} LDnST;
386
387#if USER_MODE_OPT
388static inline fault_t interpreter_read_memory(addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size){
389 switch(size) {
390 case 8:
391 value = Memory::Read8(virt_addr);
392 break;
393 case 16:
394 value = Memory::Read16(virt_addr);
395 break;
396 case 32:
397 value = Memory::Read32(virt_addr);
398 break;
399 }
400 return NO_FAULT;
401}
402
403//static inline void interpreter_write_memory(void *mem_ptr, uint32_t offset, uint32_t value, int size)
404static inline fault_t interpreter_write_memory(addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size)
405{
406 switch(size) {
407 case 8:
408 Memory::Write8(virt_addr, value & 0xff);
409 break;
410 case 16:
411 Memory::Write16(virt_addr, value & 0xffff);
412 break;
413 case 32:
414 Memory::Write32(virt_addr, value);
415 break;
416 }
417 return NO_FAULT;
418}
419
420static inline fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw){
421 *phys_addr = virt_addr;
422 return NO_FAULT;
423}
424
425#else
426fault_t interpreter_read_memory(cpu_t *cpu, addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size);
427fault_t interpreter_write_memory(cpu_t *cpu, addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size);
428fault_t interpreter_fetch(cpu_t *cpu, addr_t virt_addr, uint32_t &value, uint32_t size);
429fault_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);
430#endif
431
432typedef fault_t (*get_addr_fp_t)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw);
433
434typedef struct _ldst_inst {
435 unsigned int inst;
436 get_addr_fp_t get_addr;
437} ldst_inst;
438#define DEBUG_MSG DEBUG_LOG(ARM11, "in %s %d\n", __FUNCTION__, __LINE__); \
439 DEBUG_LOG(ARM11, "inst is %x\n", inst); \
440 CITRA_IGNORE_EXIT(0)
441
442int CondPassed(arm_processor *cpu, unsigned int cond);
443#define LnSWoUB(s) glue(LnSWoUB, s)
444#define MLnS(s) glue(MLnS, s)
445#define LdnStM(s) glue(LdnStM, s)
446
447#define W_BIT BIT(inst, 21)
448#define U_BIT BIT(inst, 23)
449#define I_BIT BIT(inst, 25)
450#define P_BIT BIT(inst, 24)
451#define OFFSET_12 BITS(inst, 0, 11)
452fault_t LnSWoUB(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
453{
454 unsigned int Rn = BITS(inst, 16, 19);
455 unsigned int addr;
456 fault_t fault;
457 if (U_BIT) {
458 addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12;
459 } else {
460 addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12;
461 }
462 //if (Rn == 15) rn += 8;
463 virt_addr = addr;
464 fault = check_address_validity(cpu, addr, &phys_addr, rw);
465 return fault;
466// return addr;
467}
468
469fault_t LnSWoUB(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
470{
471 fault_t fault;
472 unsigned int Rn = BITS(inst, 16, 19);
473 unsigned int Rm = BITS(inst, 0, 3);
474 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
475 //if (Rn == 15) rn += 8;
476 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
477 //if (Rm == 15) rm += 8;
478 unsigned int addr;
479 if (U_BIT) {
480 addr = rn + rm;
481 } else {
482 addr = rn - rm;
483 }
484 virt_addr = addr;
485 fault = check_address_validity(cpu, addr, &phys_addr, rw);
486 return fault;
487}
488
489fault_t LnSWoUB(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
490{
491 fault_t fault;
492 unsigned int Rn = BITS(inst, 16, 19);
493 unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn);
494 //if (Rn == 15) addr += 8;
495
496 virt_addr = addr;
497 fault = check_address_validity(cpu, addr, &phys_addr, rw);
498 if (fault) return fault;
499
500 if (U_BIT) {
501 cpu->Reg[Rn] += OFFSET_12;
502 } else {
503 cpu->Reg[Rn] -= OFFSET_12;
504 }
505 return fault;
506}
507
508fault_t LnSWoUB(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
509{
510 fault_t fault;
511 unsigned int Rn = BITS(inst, 16, 19);
512 unsigned int addr;
513 if (U_BIT) {
514 addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12;
515 } else {
516 addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12;
517 }
518 #if 0
519 if (Rn == 15) {
520 addr += 8;
521 }
522 #endif
523
524 virt_addr = addr;
525 fault = check_address_validity(cpu, addr, &phys_addr, rw);
526 if (fault) return fault;
527
528 if (CondPassed(cpu, BITS(inst, 28, 31))) {
529 cpu->Reg[Rn] = addr;
530 }
531 return fault;
532}
533
534fault_t MLnS(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
535{
536 fault_t fault;
537 unsigned int addr;
538 unsigned int Rn = BITS(inst, 16, 19);
539 unsigned int Rm = BITS(inst, 0, 3);
540 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
541 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
542 //if (Rn == 15) rn += 8;
543 //if (Rm == 15) rm += 8;
544 if (U_BIT) {
545 addr = rn + rm;
546 } else
547 addr = rn - rm;
548 if(BIT(inst, 20)){ /* L BIT */
549 }
550 if(BIT(inst, 6)){ /* Sign Bit */
551 }
552 if(BIT(inst, 5)){ /* Half Bit */
553 }
554
555 virt_addr = addr;
556 fault = check_address_validity(cpu, addr, &phys_addr, rw);
557 if (fault) return fault;
558
559 if (CondPassed(cpu, BITS(inst, 28, 31))) {
560 cpu->Reg[Rn] = addr;
561 }
562 return fault;
563}
564
565fault_t LnSWoUB(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
566{
567 fault_t fault;
568 unsigned int Rn = BITS(inst, 16, 19);
569 unsigned int Rm = BITS(inst, 0, 3);
570 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
571 //if (Rn == 15) rn += 8;
572 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
573 //if (Rm == 15) rm += 8;
574 unsigned int addr;
575 if (U_BIT) {
576 addr = rn + rm;
577 } else {
578 addr = rn - rm;
579 }
580 virt_addr = addr;
581 fault = check_address_validity(cpu, addr, &phys_addr, rw);
582 if(fault)
583 return fault;
584 if (CondPassed(cpu, BITS(inst, 28, 31))) {
585 cpu->Reg[Rn] = addr;
586 }
587 return fault;
588}
589fault_t LnSWoUB(ScaledRegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
590{
591 fault_t fault;
592 unsigned int shift = BITS(inst, 5, 6);
593 unsigned int shift_imm = BITS(inst, 7, 11);
594 unsigned int Rn = BITS(inst, 16, 19);
595 unsigned int Rm = BITS(inst, 0, 3);
596 unsigned int index;
597 unsigned int addr;
598
599 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
600 //if (Rm == 15) rm += 8;
601 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
602 //if (Rn == 15) rn += 8;
603 switch (shift) {
604 case 0:
605 //DEBUG_MSG;
606 index = rm << shift_imm;
607 break;
608 case 1:
609// DEBUG_MSG;
610 if (shift_imm == 0) {
611 index = 0;
612 } else {
613 index = rm >> shift_imm;
614 }
615 break;
616 case 2:
617 DEBUG_MSG;
618 break;
619 case 3:
620 DEBUG_MSG;
621 break;
622 }
623 if (U_BIT) {
624 addr = rn + index;
625 } else
626 addr = rn - index;
627 virt_addr = addr;
628 fault = check_address_validity(cpu, addr, &phys_addr, rw);
629 if(fault)
630 return fault;
631 if (CondPassed(cpu, BITS(inst, 28, 31))) {
632 cpu->Reg[Rn] = addr;
633 }
634
635 return fault;
636}
637
638fault_t LnSWoUB(ScaledRegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
639{
640 fault_t fault;
641 unsigned int shift = BITS(inst, 5, 6);
642 unsigned int shift_imm = BITS(inst, 7, 11);
643 unsigned int Rn = BITS(inst, 16, 19);
644 unsigned int Rm = BITS(inst, 0, 3);
645 unsigned int index;
646 unsigned int addr;
647
648 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
649 //if (Rm == 15) rm += 8;
650 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
651 //if (Rn == 15) rn += 8;
652 addr = rn;
653 switch (shift) {
654 case 0:
655 //DEBUG_MSG;
656 index = rm << shift_imm;
657 break;
658 case 1:
659// DEBUG_MSG;
660 if (shift_imm == 0) {
661 index = 0;
662 } else {
663 index = rm >> shift_imm;
664 }
665 break;
666 case 2:
667 DEBUG_MSG;
668 break;
669 case 3:
670 DEBUG_MSG;
671 break;
672 }
673 virt_addr = addr;
674 fault = check_address_validity(cpu, addr, &phys_addr, rw);
675 if(fault)
676 return fault;
677 if (CondPassed(cpu, BITS(inst, 28, 31))) {
678 if (U_BIT)
679 cpu->Reg[Rn] += index;
680 else
681 cpu->Reg[Rn] -= index;
682 }
683
684 return fault;
685}
686
687fault_t LnSWoUB(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
688{
689 fault_t fault;
690 unsigned int Rn = BITS(inst, 16, 19);
691 unsigned int Rm = BITS(inst, 0, 3);
692 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
693 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
694
695 unsigned int addr = rn;
696 virt_addr = addr;
697 fault = check_address_validity(cpu, addr, &phys_addr, rw);
698 if (fault) return fault;
699
700 if (CondPassed(cpu, BITS(inst, 28, 31))) {
701 if (U_BIT) {
702 cpu->Reg[Rn] += rm;
703 } else {
704 cpu->Reg[Rn] -= rm;
705 }
706 }
707 return fault;
708}
709
710fault_t MLnS(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
711{
712 fault_t fault;
713 unsigned int immedL = BITS(inst, 0, 3);
714 unsigned int immedH = BITS(inst, 8, 11);
715
716 unsigned int Rn = BITS(inst, 16, 19);
717 unsigned int addr;
718
719 unsigned int offset_8 = (immedH << 4) | immedL;
720 if (U_BIT) {
721 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8;
722 } else
723 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8;
724 #if 0
725 if (Rn == 15) {
726 addr += 8;
727 }
728 #endif
729 virt_addr = addr;
730 fault = check_address_validity(cpu, addr, &phys_addr, rw);
731 return fault;
732}
733
734fault_t MLnS(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
735{
736 fault_t fault;
737 unsigned int addr;
738 unsigned int Rn = BITS(inst, 16, 19);
739 unsigned int Rm = BITS(inst, 0, 3);
740 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
741 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
742 //if (Rn == 15) rn += 8;
743 //if (Rm == 15) rm += 8;
744 if (U_BIT) {
745 addr = rn + rm;
746 } else
747 addr = rn - rm;
748 if(BIT(inst, 20)){ /* L BIT */
749 }
750 if(BIT(inst, 6)){ /* Sign Bit */
751 }
752 if(BIT(inst, 5)){ /* Half Bit */
753 }
754 virt_addr = addr;
755 fault = check_address_validity(cpu, addr, &phys_addr, rw);
756 return fault;
757}
758
759fault_t MLnS(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
760{
761 fault_t fault;
762 unsigned int Rn = BITS(inst, 16, 19);
763 unsigned int immedH = BITS(inst, 8, 11);
764 unsigned int immedL = BITS(inst, 0, 3);
765 unsigned int addr;
766 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
767 //if (Rn == 15) rn += 8;
768
769// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
770 unsigned int offset_8 = (immedH << 4) | immedL;
771 if (U_BIT) {
772 addr = rn + offset_8;
773 } else
774 addr = rn - offset_8;
775
776 virt_addr = addr;
777 fault = check_address_validity(cpu, addr, &phys_addr, rw);
778 if (fault) return fault;
779
780 if (CondPassed(cpu, BITS(inst, 28, 31))) {
781 cpu->Reg[Rn] = addr;
782 }
783 return fault;
784}
785
786fault_t MLnS(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
787{
788 fault_t fault;
789 unsigned int Rn = BITS(inst, 16, 19);
790 unsigned int immedH = BITS(inst, 8, 11);
791 unsigned int immedL = BITS(inst, 0, 3);
792 unsigned int addr;
793 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
794 addr = rn;
795
796 virt_addr = addr;
797 fault = check_address_validity(cpu, addr, &phys_addr, rw);
798 if (fault) return fault;
799
800 if (CondPassed(cpu, BITS(inst, 28, 31))) {
801 unsigned int offset_8 = (immedH << 4) | immedL;
802 if (U_BIT) {
803 rn += offset_8;
804 } else {
805 rn -= offset_8;
806 }
807 cpu->Reg[Rn] = rn;
808 }
809
810 return fault;
811}
812fault_t MLnS(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
813{
814 fault_t fault;
815 unsigned int Rn = BITS(inst, 16, 19);
816 unsigned int Rm = BITS(inst, 0, 3);
817 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
818 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
819
820 unsigned int addr = rn;
821 virt_addr = addr;
822 fault = check_address_validity(cpu, addr, &phys_addr, rw);
823 if (fault) return fault;
824
825 if (CondPassed(cpu, BITS(inst, 28, 31))) {
826 if (U_BIT) {
827 cpu->Reg[Rn] += rm;
828 } else {
829 cpu->Reg[Rn] -= rm;
830 }
831 }
832 return fault;
833}
834
835fault_t LdnStM(DecrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
836{
837 fault_t fault;
838 unsigned int Rn = BITS(inst, 16, 19);
839 unsigned int i = BITS(inst, 0, 15);
840 int count = 0;
841 while(i) {
842 if(i & 1) count ++;
843 i = i >> 1;
844 }
845 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
846 //if (Rn == 15) rn += 8;
847 unsigned int start_addr = rn - count * 4;
848 unsigned int end_addr = rn - 4;
849
850 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
851 virt_addr = end_addr;
852 if (fault) return fault;
853
854 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
855 virt_addr = start_addr;
856 if (fault) return fault;
857
858 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
859 cpu->Reg[Rn] -= count * 4;
860 }
861
862 return fault;
863}
864
865fault_t LdnStM(IncrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
866{
867 fault_t fault;
868 unsigned int Rn = BITS(inst, 16, 19);
869 unsigned int i = BITS(inst, 0, 15);
870 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
871 //if (Rn == 15) rn += 8;
872 int count = 0;
873 while(i) {
874 if(i & 1) count ++;
875 i = i >> 1;
876 }
877
878 unsigned int start_addr = rn + 4;
879 unsigned int end_addr = rn + count * 4;
880
881 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
882 virt_addr = end_addr;
883 if (fault) return fault;
884
885 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
886 virt_addr = start_addr;
887 if (fault) return fault;
888
889 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
890 cpu->Reg[Rn] += count * 4;
891 }
892 return fault;
893}
894
895fault_t LdnStM(IncrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
896{
897 fault_t fault;
898 unsigned int Rn = BITS(inst, 16, 19);
899 unsigned int i = BITS(inst, 0, 15);
900 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
901 int count = 0;
902 while(i) {
903 if(i & 1) count ++;
904 i = i >> 1;
905 }
906 //if (Rn == 15) rn += 8;
907 unsigned int start_addr = rn;
908 unsigned int end_addr = rn + count * 4 - 4;
909
910 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
911 virt_addr = end_addr;
912 if (fault) return fault;
913
914 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
915 virt_addr = start_addr;
916 if (fault) return fault;
917
918 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
919 cpu->Reg[Rn] += count * 4;
920 }
921 return fault;
922}
923
924fault_t LdnStM(DecrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
925{
926 fault_t fault;
927 unsigned int Rn = BITS(inst, 16, 19);
928 unsigned int i = BITS(inst, 0, 15);
929 int count = 0;
930 while(i) {
931 if(i & 1) count ++;
932 i = i >> 1;
933 }
934 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
935 //if (Rn == 15) rn += 8;
936 unsigned int start_addr = rn - count * 4 + 4;
937 unsigned int end_addr = rn;
938
939 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
940 virt_addr = end_addr;
941 if (fault) return fault;
942
943 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
944 if (fault) return fault;
945 virt_addr = start_addr;
946
947 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
948 cpu->Reg[Rn] -= count * 4;
949 }
950 return fault;
951}
952
953fault_t LnSWoUB(ScaledRegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
954{
955 fault_t fault;
956 unsigned int shift = BITS(inst, 5, 6);
957 unsigned int shift_imm = BITS(inst, 7, 11);
958 unsigned int Rn = BITS(inst, 16, 19);
959 unsigned int Rm = BITS(inst, 0, 3);
960 unsigned int index;
961 unsigned int addr;
962
963 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
964 //if (Rm == 15) rm += 8;
965 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
966 //if (Rn == 15) rn += 8;
967 switch (shift) {
968 case 0:
969 //DEBUG_MSG;
970 index = rm << shift_imm;
971 break;
972 case 1:
973// DEBUG_MSG;
974 if (shift_imm == 0) {
975 index = 0;
976 } else {
977 index = rm >> shift_imm;
978 }
979 break;
980 case 2:
981 if (shift_imm == 0){ /* ASR #32 */
982 if (rm >> 31)
983 index = 0xFFFFFFFF;
984 else
985 index = 0;
986 }
987 else {
988 index = static_cast<int>(rm) >> shift_imm;
989 }
990 break;
991 case 3:
992 DEBUG_MSG;
993 break;
994 }
995 if (U_BIT) {
996 addr = rn + index;
997 } else
998 addr = rn - index;
999 virt_addr = addr;
1000 fault = check_address_validity(cpu, addr, &phys_addr, rw);
1001 return fault;
1002}
1003
1004#define ISNEG(n) (n < 0)
1005#define ISPOS(n) (n >= 0)
1006
1007//enum {
1008// COND = (1 << 0),
1009// NON_BRANCH = (1 << 1),
1010// DIRECT_BRANCH = (1 << 2),
1011// INDIRECT_BRANCH = (1 << 3),
1012// CALL = (1 << 4),
1013// RET = (1 << 5),
1014// END_OF_PAGE = (1 << 6),
1015// THUMB = (1 << 7)
1016//};
1017
1018typedef struct _arm_inst {
1019 unsigned int idx;
1020 unsigned int cond;
1021 int br;
1022 int load_r15;
1023 char component[0];
1024} arm_inst;
1025
1026typedef struct _adc_inst {
1027 unsigned int I;
1028 unsigned int S;
1029 unsigned int Rn;
1030 unsigned int Rd;
1031 unsigned int shifter_operand;
1032 shtop_fp_t shtop_func;
1033} adc_inst;
1034
1035typedef struct _add_inst {
1036 unsigned int I;
1037 unsigned int S;
1038 unsigned int Rn;
1039 unsigned int Rd;
1040 unsigned int shifter_operand;
1041 shtop_fp_t shtop_func;
1042} add_inst;
1043
1044typedef struct _orr_inst {
1045 unsigned int I;
1046 unsigned int S;
1047 unsigned int Rn;
1048 unsigned int Rd;
1049 unsigned int shifter_operand;
1050 shtop_fp_t shtop_func;
1051} orr_inst;
1052
1053typedef struct _and_inst {
1054 unsigned int I;
1055 unsigned int S;
1056 unsigned int Rn;
1057 unsigned int Rd;
1058 unsigned int shifter_operand;
1059 shtop_fp_t shtop_func;
1060} and_inst;
1061
1062typedef struct _eor_inst {
1063 unsigned int I;
1064 unsigned int S;
1065 unsigned int Rn;
1066 unsigned int Rd;
1067 unsigned int shifter_operand;
1068 shtop_fp_t shtop_func;
1069} eor_inst;
1070
1071typedef struct _bbl_inst {
1072 unsigned int L;
1073 int signed_immed_24;
1074 unsigned int next_addr;
1075 unsigned int jmp_addr;
1076} bbl_inst;
1077
1078typedef struct _bx_inst {
1079 unsigned int Rm;
1080} bx_inst;
1081
1082typedef struct _blx_inst {
1083 union {
1084 int32_t signed_immed_24;
1085 uint32_t Rm;
1086 } val;
1087 unsigned int inst;
1088} blx_inst;
1089
1090typedef struct _clz_inst {
1091 unsigned int Rm;
1092 unsigned int Rd;
1093} clz_inst;
1094
1095typedef struct _cps_inst {
1096 unsigned int imod0;
1097 unsigned int imod1;
1098 unsigned int mmod;
1099 unsigned int A, I, F;
1100 unsigned int mode;
1101} cps_inst;
1102
1103typedef struct _clrex_inst {
1104} clrex_inst;
1105
1106typedef struct _cpy_inst {
1107 unsigned int Rm;
1108 unsigned int Rd;
1109} cpy_inst;
1110
1111typedef struct _bic_inst {
1112 unsigned int I;
1113 unsigned int S;
1114 unsigned int Rn;
1115 unsigned int Rd;
1116 unsigned int shifter_operand;
1117 shtop_fp_t shtop_func;
1118} bic_inst;
1119
1120typedef struct _sub_inst {
1121 unsigned int I;
1122 unsigned int S;
1123 unsigned int Rn;
1124 unsigned int Rd;
1125 unsigned int shifter_operand;
1126 shtop_fp_t shtop_func;
1127} sub_inst;
1128
1129typedef struct _tst_inst {
1130 unsigned int I;
1131 unsigned int S;
1132 unsigned int Rn;
1133 unsigned int Rd;
1134 unsigned int shifter_operand;
1135 shtop_fp_t shtop_func;
1136} tst_inst;
1137
1138typedef struct _cmn_inst {
1139 unsigned int I;
1140 //unsigned int S;
1141 unsigned int Rn;
1142 //unsigned int Rd;
1143 unsigned int shifter_operand;
1144 shtop_fp_t shtop_func;
1145} cmn_inst;
1146
1147typedef struct _teq_inst {
1148 unsigned int I;
1149 unsigned int Rn;
1150 unsigned int shifter_operand;
1151 shtop_fp_t shtop_func;
1152} teq_inst;
1153
1154typedef struct _stm_inst {
1155 unsigned int inst;
1156} stm_inst;
1157
1158struct bkpt_inst {
1159};
1160
1161struct blx1_inst {
1162 unsigned int addr;
1163};
1164
1165struct blx2_inst {
1166 unsigned int Rm;
1167};
1168
1169typedef struct _stc_inst {
1170} stc_inst;
1171
1172typedef struct _ldc_inst {
1173} ldc_inst;
1174
1175typedef struct _swi_inst {
1176 unsigned int num;
1177} swi_inst;
1178
1179typedef struct _cmp_inst {
1180 unsigned int I;
1181 unsigned int Rn;
1182 unsigned int shifter_operand;
1183 shtop_fp_t shtop_func;
1184} cmp_inst;
1185
1186typedef struct _mov_inst {
1187 unsigned int I;
1188 unsigned int S;
1189 unsigned int Rd;
1190 unsigned int shifter_operand;
1191 shtop_fp_t shtop_func;
1192} mov_inst;
1193
1194typedef struct _mvn_inst {
1195 unsigned int I;
1196 unsigned int S;
1197 unsigned int Rd;
1198 unsigned int shifter_operand;
1199 shtop_fp_t shtop_func;
1200} mvn_inst;
1201
1202typedef struct _rev_inst {
1203 unsigned int Rd;
1204 unsigned int Rm;
1205} rev_inst;
1206
1207typedef struct _rsb_inst {
1208 unsigned int I;
1209 unsigned int S;
1210 unsigned int Rn;
1211 unsigned int Rd;
1212 unsigned int shifter_operand;
1213 shtop_fp_t shtop_func;
1214} rsb_inst;
1215
1216typedef struct _rsc_inst {
1217 unsigned int I;
1218 unsigned int S;
1219 unsigned int Rn;
1220 unsigned int Rd;
1221 unsigned int shifter_operand;
1222 shtop_fp_t shtop_func;
1223} rsc_inst;
1224
1225typedef struct _sbc_inst {
1226 unsigned int I;
1227 unsigned int S;
1228 unsigned int Rn;
1229 unsigned int Rd;
1230 unsigned int shifter_operand;
1231 shtop_fp_t shtop_func;
1232} sbc_inst;
1233
1234typedef struct _mul_inst {
1235 unsigned int S;
1236 unsigned int Rd;
1237 unsigned int Rs;
1238 unsigned int Rm;
1239} mul_inst;
1240
1241typedef struct _smul_inst {
1242 unsigned int Rd;
1243 unsigned int Rs;
1244 unsigned int Rm;
1245 unsigned int x;
1246 unsigned int y;
1247} smul_inst;
1248
1249typedef struct _umull_inst {
1250 unsigned int S;
1251 unsigned int RdHi;
1252 unsigned int RdLo;
1253 unsigned int Rs;
1254 unsigned int Rm;
1255} umull_inst;
1256typedef struct _smlad_inst {
1257 unsigned int m;
1258 unsigned int Rm;
1259 unsigned int Rd;
1260 unsigned int Ra;
1261 unsigned int Rn;
1262} smlad_inst;
1263
1264typedef struct _smla_inst {
1265 unsigned int x;
1266 unsigned int y;
1267 unsigned int Rm;
1268 unsigned int Rd;
1269 unsigned int Rs;
1270 unsigned int Rn;
1271} smla_inst;
1272
1273typedef struct _umlal_inst {
1274 unsigned int S;
1275 unsigned int Rm;
1276 unsigned int Rs;
1277 unsigned int RdHi;
1278 unsigned int RdLo;
1279} umlal_inst;
1280
1281typedef struct _smlal_inst {
1282 unsigned int S;
1283 unsigned int Rm;
1284 unsigned int Rs;
1285 unsigned int RdHi;
1286 unsigned int RdLo;
1287} smlal_inst;
1288
1289typedef struct _mla_inst {
1290 unsigned int S;
1291 unsigned int Rn;
1292 unsigned int Rd;
1293 unsigned int Rs;
1294 unsigned int Rm;
1295} mla_inst;
1296
1297typedef struct _mrc_inst {
1298 unsigned int opcode_1;
1299 unsigned int opcode_2;
1300 unsigned int cp_num;
1301 unsigned int crn;
1302 unsigned int crm;
1303 unsigned int Rd;
1304 unsigned int inst;
1305} mrc_inst;
1306
1307typedef struct _mcr_inst {
1308 unsigned int opcode_1;
1309 unsigned int opcode_2;
1310 unsigned int cp_num;
1311 unsigned int crn;
1312 unsigned int crm;
1313 unsigned int Rd;
1314 unsigned int inst;
1315} mcr_inst;
1316
1317typedef struct _mrs_inst {
1318 unsigned int R;
1319 unsigned int Rd;
1320} mrs_inst;
1321
1322typedef struct _msr_inst {
1323 unsigned int field_mask;
1324 unsigned int R;
1325 unsigned int inst;
1326} msr_inst;
1327
1328typedef struct _pld_inst {
1329} pld_inst;
1330
1331typedef struct _sxtb_inst {
1332 unsigned int Rd;
1333 unsigned int Rm;
1334 unsigned int rotate;
1335} sxtb_inst;
1336
1337typedef struct _sxtab_inst {
1338 unsigned int Rd;
1339 unsigned int Rn;
1340 unsigned int Rm;
1341 unsigned rotate;
1342} sxtab_inst;
1343
1344typedef struct _sxtah_inst {
1345 unsigned int Rd;
1346 unsigned int Rn;
1347 unsigned int Rm;
1348 unsigned int rotate;
1349} sxtah_inst;
1350
1351typedef struct _sxth_inst {
1352 unsigned int Rd;
1353 unsigned int Rm;
1354 unsigned int rotate;
1355} sxth_inst;
1356
1357typedef struct _uxtab_inst {
1358 unsigned int Rn;
1359 unsigned int Rd;
1360 unsigned int rotate;
1361 unsigned int Rm;
1362} uxtab_inst;
1363
1364typedef struct _uxtah_inst {
1365 unsigned int Rn;
1366 unsigned int Rd;
1367 unsigned int rotate;
1368 unsigned int Rm;
1369} uxtah_inst;
1370
1371typedef struct _uxth_inst {
1372 unsigned int Rd;
1373 unsigned int Rm;
1374 unsigned int rotate;
1375} uxth_inst;
1376
1377typedef struct _cdp_inst {
1378 unsigned int opcode_1;
1379 unsigned int CRn;
1380 unsigned int CRd;
1381 unsigned int cp_num;
1382 unsigned int opcode_2;
1383 unsigned int CRm;
1384 uint32 inst;
1385}cdp_inst;
1386
1387typedef struct _uxtb_inst {
1388 unsigned int Rd;
1389 unsigned int Rm;
1390 unsigned int rotate;
1391} uxtb_inst;
1392
1393typedef struct _swp_inst {
1394 unsigned int Rn;
1395 unsigned int Rd;
1396 unsigned int Rm;
1397} swp_inst;
1398
1399typedef struct _b_2_thumb {
1400 unsigned int imm;
1401}b_2_thumb;
1402typedef struct _b_cond_thumb {
1403 unsigned int imm;
1404 unsigned int cond;
1405}b_cond_thumb;
1406
1407typedef struct _bl_1_thumb {
1408 unsigned int imm;
1409}bl_1_thumb;
1410typedef struct _bl_2_thumb {
1411 unsigned int imm;
1412}bl_2_thumb;
1413typedef struct _blx_1_thumb {
1414 unsigned int imm;
1415 unsigned int instr;
1416}blx_1_thumb;
1417
1418typedef arm_inst * ARM_INST_PTR;
1419
1420#define CACHE_BUFFER_SIZE (64 * 1024 * 2000)
1421char inst_buf[CACHE_BUFFER_SIZE];
1422int top = 0;
1423inline void *AllocBuffer(unsigned int size)
1424{
1425 int start = top;
1426 top += size;
1427 if (top > CACHE_BUFFER_SIZE) {
1428 DEBUG_LOG(ARM11, "inst_buf is full\n");
1429 CITRA_IGNORE_EXIT(-1);
1430 }
1431 return (void *)&inst_buf[start];
1432}
1433
1434int CondPassed(arm_processor *cpu, unsigned int cond)
1435{
1436 #define NFLAG cpu->NFlag
1437 #define ZFLAG cpu->ZFlag
1438 #define CFLAG cpu->CFlag
1439 #define VFLAG cpu->VFlag
1440 int temp;
1441 switch (cond) {
1442 case 0x0:
1443 temp = ZFLAG;
1444 break;
1445 case 0x1: /* NE */
1446 temp = !ZFLAG;
1447 break;
1448 case 0x6: /* VS */
1449 temp = VFLAG;
1450 break;
1451 case 0x7: /* VC */
1452 temp = !VFLAG;
1453 break;
1454 case 0x4: /* MI */
1455 temp = NFLAG;
1456 break;
1457 case 0x5: /* PL */
1458 temp = !NFLAG;
1459 break;
1460 case 0x2: /* CS */
1461 temp = CFLAG;
1462 break;
1463 case 0x3: /* CC */
1464 temp = !CFLAG;
1465 break;
1466 case 0x8: /* HI */
1467 temp = (CFLAG && !ZFLAG);
1468 break;
1469 case 0x9: /* LS */
1470 temp = (!CFLAG || ZFLAG);
1471 break;
1472 case 0xa: /* GE */
1473 temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
1474 break;
1475 case 0xb: /* LT */
1476 temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
1477 break;
1478 case 0xc: /* GT */
1479 temp = ((!NFLAG && !VFLAG && !ZFLAG)
1480 || (NFLAG && VFLAG && !ZFLAG));
1481 break;
1482 case 0xd: /* LE */
1483 temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG))
1484 || ZFLAG;
1485 break;
1486 case 0xe: /* AL */
1487 temp = 1;
1488 break;
1489 case 0xf:
1490// DEBUG_LOG(ARM11, "inst is %x\n");
1491// DEBUG_LOG(ARM11, "icounter is %lld\n", cpu->icounter);
1492// CITRA_IGNORE_EXIT(-1);
1493 temp = 1;
1494 break;
1495 }
1496 return temp;
1497}
1498
1499enum DECODE_STATUS {
1500 DECODE_SUCCESS,
1501 DECODE_FAILURE
1502};
1503
1504int decode_arm_instr(uint32_t instr, int32_t *idx);
1505
1506shtop_fp_t get_shtop(unsigned int inst)
1507{
1508 if (BIT(inst, 25)) {
1509 return DPO(Immediate);
1510 } else if (BITS(inst, 4, 11) == 0) {
1511 return DPO(Register);
1512 } else if (BITS(inst, 4, 6) == 0) {
1513 return DPO(LogicalShiftLeftByImmediate);
1514 } else if (BITS(inst, 4, 7) == 1) {
1515 return DPO(LogicalShiftLeftByRegister);
1516 } else if (BITS(inst, 4, 6) == 2) {
1517 return DPO(LogicalShiftRightByImmediate);
1518 } else if (BITS(inst, 4, 7) == 3) {
1519 return DPO(LogicalShiftRightByRegister);
1520 } else if (BITS(inst, 4, 6) == 4) {
1521 return DPO(ArithmeticShiftRightByImmediate);
1522 } else if (BITS(inst, 4, 7) == 5) {
1523 return DPO(ArithmeticShiftRightByRegister);
1524 } else if (BITS(inst, 4, 6) == 6) {
1525 return DPO(RotateRightByImmediate);
1526 } else if (BITS(inst, 4, 7) == 7) {
1527 return DPO(RotateRightByRegister);
1528 }
1529 return NULL;
1530}
1531
1532get_addr_fp_t get_calc_addr_op(unsigned int inst)
1533{
1534 /* 1 */
1535 if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) {
1536// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1537 return LnSWoUB(ImmediateOffset);
1538 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
1539// DEBUG_MSG;
1540// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1541 return LnSWoUB(RegisterOffset);
1542 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) {
1543// DEBUG_MSG;
1544// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1545 return LnSWoUB(ScaledRegisterOffset);
1546 } else if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 1) {
1547// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1548 return LnSWoUB(ImmediatePreIndexed);
1549 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BITS(inst, 4, 11) == 0) {
1550 return LnSWoUB(RegisterPreIndexed);
1551 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BIT(inst, 4) == 0) {
1552 return LnSWoUB(ScaledRegisterPreIndexed);
1553 } else if (BITS(inst, 24, 27) == 4 && BIT(inst, 21) == 0) {
1554 return LnSWoUB(ImmediatePostIndexed);
1555 } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
1556// DEBUG_MSG;
1557 return LnSWoUB(RegisterPostIndexed);
1558 } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) {
1559 return LnSWoUB(ScaledRegisterPostIndexed);
1560// DEBUG_MSG;
1561 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1562 /* 2 */
1563// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1564 return MLnS(ImmediateOffset);
1565// DEBUG_MSG;
1566 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1567// DEBUG_LOG(ARM11, "line is %d\n", __LINE__);
1568 return MLnS(RegisterOffset);
1569// DEBUG_MSG;
1570 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 3 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1571// DEBUG_LOG(ARM11, "line is %d\n", __LINE__);
1572 return MLnS(ImmediatePreIndexed);
1573// DEBUG_MSG;
1574 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 1 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1575 return MLnS(RegisterPreIndexed);
1576 } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1577// DEBUG_MSG;
1578 return MLnS(ImmediatePostIndexed);
1579 } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1580 //DEBUG_MSG;
1581 return MLnS(RegisterPostIndexed);
1582 } else if (BITS(inst, 23, 27) == 0x11) {
1583 /* 3 */
1584// DEBUG_MSG;
1585// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1586 return LdnStM(IncrementAfter);
1587 } else if (BITS(inst, 23, 27) == 0x13) {
1588// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1589 return LdnStM(IncrementBefore);
1590// DEBUG_MSG;
1591 } else if (BITS(inst, 23, 27) == 0x10) {
1592// DEBUG_MSG;
1593// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1594 return LdnStM(DecrementAfter);
1595 } else if (BITS(inst, 23, 27) == 0x12) {
1596// DEBUG_MSG;
1597// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1598 return LdnStM(DecrementBefore);
1599 }
1600 #if 0
1601 DEBUG_LOG(ARM11, "In %s Unknown addressing mode\n", __FUNCTION__);
1602 DEBUG_LOG(ARM11, "inst:%x\n", inst);
1603 CITRA_IGNORE_EXIT(-1);
1604 #endif
1605 return NULL;
1606}
1607
1608#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s)
1609
1610#define CHECK_RN (inst_cream->Rn == 15)
1611#define CHECK_RM (inst_cream->Rm == 15)
1612#define CHECK_RS (inst_cream->Rs == 15)
1613
1614
1615ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index)
1616{
1617 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst));
1618 adc_inst *inst_cream = (adc_inst *)inst_base->component;
1619
1620 inst_base->cond = BITS(inst, 28, 31);
1621 inst_base->idx = index;
1622 inst_base->br = NON_BRANCH;
1623 inst_base->load_r15 = 0;
1624
1625 inst_cream->I = BIT(inst, 25);
1626 inst_cream->S = BIT(inst, 20);
1627 inst_cream->Rn = BITS(inst, 16, 19);
1628 inst_cream->Rd = BITS(inst, 12, 15);
1629 if (CHECK_RN)
1630 inst_base->load_r15 = 1;
1631 inst_cream->shifter_operand = BITS(inst, 0, 11);
1632 inst_cream->shtop_func = get_shtop(inst);
1633 if (inst_cream->Rd == 15) {
1634 inst_base->br = INDIRECT_BRANCH;
1635 }
1636 return inst_base;
1637}
1638ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index)
1639{
1640 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst));
1641 add_inst *inst_cream = (add_inst *)inst_base->component;
1642
1643 inst_base->cond = BITS(inst, 28, 31);
1644 inst_base->idx = index;
1645 inst_base->br = NON_BRANCH;
1646 inst_base->load_r15 = 0;
1647
1648 inst_cream->I = BIT(inst, 25);
1649 inst_cream->S = BIT(inst, 20);
1650 inst_cream->Rn = BITS(inst, 16, 19);
1651 inst_cream->Rd = BITS(inst, 12, 15);
1652 if (CHECK_RN)
1653 inst_base->load_r15 = 1;
1654 inst_cream->shifter_operand = BITS(inst, 0, 11);
1655 inst_cream->shtop_func = get_shtop(inst);
1656 if (inst_cream->Rd == 15) {
1657 inst_base->br = INDIRECT_BRANCH;
1658 }
1659 return inst_base;
1660}
1661ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
1662{
1663 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst));
1664 and_inst *inst_cream = (and_inst *)inst_base->component;
1665
1666 inst_base->cond = BITS(inst, 28, 31);
1667 inst_base->idx = index;
1668 inst_base->br = NON_BRANCH;
1669 inst_base->load_r15 = 0;
1670
1671 inst_cream->I = BIT(inst, 25);
1672 inst_cream->S = BIT(inst, 20);
1673 inst_cream->Rn = BITS(inst, 16, 19);
1674 inst_cream->Rd = BITS(inst, 12, 15);
1675 if (CHECK_RN)
1676 inst_base->load_r15 = 1;
1677 inst_cream->shifter_operand = BITS(inst, 0, 11);
1678 inst_cream->shtop_func = get_shtop(inst);
1679 if (inst_cream->Rd == 15)
1680 inst_base->br = INDIRECT_BRANCH;
1681 return inst_base;
1682}
1683ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index)
1684{
1685 #define POSBRANCH ((inst & 0x7fffff) << 2)
1686 #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2)
1687
1688 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst));
1689 bbl_inst *inst_cream = (bbl_inst *)inst_base->component;
1690
1691 inst_base->cond = BITS(inst, 28, 31);
1692 inst_base->idx = index;
1693 inst_base->br = DIRECT_BRANCH;
1694
1695 if (BIT(inst, 24))
1696 inst_base->br = CALL;
1697 if (BITS(inst, 28, 31) <= 0xe)
1698 inst_base->br |= COND;
1699
1700 inst_cream->L = BIT(inst, 24);
1701 inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH;
1702
1703 return inst_base;
1704}
1705ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
1706{
1707 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst));
1708 bic_inst *inst_cream = (bic_inst *)inst_base->component;
1709
1710 inst_base->cond = BITS(inst, 28, 31);
1711 inst_base->idx = index;
1712 inst_base->br = NON_BRANCH;
1713 inst_base->load_r15 = 0;
1714
1715 inst_cream->I = BIT(inst, 25);
1716 inst_cream->S = BIT(inst, 20);
1717 inst_cream->Rn = BITS(inst, 16, 19);
1718 inst_cream->Rd = BITS(inst, 12, 15);
1719 if (CHECK_RN)
1720 inst_base->load_r15 = 1;
1721 inst_cream->shifter_operand = BITS(inst, 0, 11);
1722 inst_cream->shtop_func = get_shtop(inst);
1723
1724 if (inst_cream->Rd == 15)
1725 inst_base->br = INDIRECT_BRANCH;
1726 return inst_base;
1727}
1728ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
1729ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index)
1730{
1731 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst));
1732 blx_inst *inst_cream = (blx_inst *)inst_base->component;
1733
1734 inst_base->cond = BITS(inst, 28, 31);
1735 inst_base->idx = index;
1736 inst_base->br = INDIRECT_BRANCH;
1737
1738 inst_cream->inst = inst;
1739 if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
1740 inst_cream->val.Rm = BITS(inst, 0, 3);
1741 } else {
1742 inst_cream->val.signed_immed_24 = BITS(inst, 0, 23);
1743 //DEBUG_LOG(ARM11, " blx inst is %x\n", inst);
1744 //CITRA_IGNORE_EXIT(-1);
1745// DEBUG_MSG;
1746 }
1747
1748 return inst_base;
1749}
1750ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index)
1751{
1752 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst));
1753 bx_inst *inst_cream = (bx_inst *)inst_base->component;
1754
1755 inst_base->cond = BITS(inst, 28, 31);
1756 inst_base->idx = index;
1757 inst_base->br = INDIRECT_BRANCH;
1758
1759 inst_cream->Rm = BITS(inst, 0, 3);
1760
1761 return inst_base;
1762}
1763ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
1764ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index){
1765 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst));
1766 cdp_inst *inst_cream = (cdp_inst *)inst_base->component;
1767 inst_base->cond = BITS(inst, 28, 31);
1768 inst_base->idx = index;
1769 inst_base->br = NON_BRANCH;
1770 inst_base->load_r15 = 0;
1771
1772 inst_cream->CRm = BITS(inst, 0, 3);
1773 inst_cream->CRd = BITS(inst, 12, 15);
1774 inst_cream->CRn = BITS(inst, 16, 19);
1775 inst_cream->cp_num = BITS(inst, 8, 11);
1776 inst_cream->opcode_2 = BITS(inst, 5, 7);
1777 inst_cream->opcode_1 = BITS(inst, 20, 23);
1778 inst_cream->inst = inst;
1779
1780 DEBUG_LOG(ARM11, "in func %s inst %x index %x\n", __FUNCTION__, inst, index);
1781 return inst_base;
1782}
1783ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index)
1784{
1785 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst));
1786 inst_base->cond = BITS(inst, 28, 31);
1787 inst_base->idx = index;
1788 inst_base->br = NON_BRANCH;
1789
1790 return inst_base;
1791}
1792ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index)
1793{
1794 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst));
1795 clz_inst *inst_cream = (clz_inst *)inst_base->component;
1796
1797 inst_base->cond = BITS(inst, 28, 31);
1798 inst_base->idx = index;
1799 inst_base->br = NON_BRANCH;
1800 inst_base->load_r15 = 0;
1801
1802 inst_cream->Rm = BITS(inst, 0, 3);
1803 inst_cream->Rd = BITS(inst, 12, 15);
1804 if (CHECK_RM)
1805 inst_base->load_r15 = 1;
1806
1807 return inst_base;
1808}
1809ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index)
1810{
1811 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst));
1812 cmn_inst *inst_cream = (cmn_inst *)inst_base->component;
1813
1814 inst_base->cond = BITS(inst, 28, 31);
1815 inst_base->idx = index;
1816 inst_base->br = NON_BRANCH;
1817 inst_base->load_r15 = 0;
1818
1819 inst_cream->I = BIT(inst, 25);
1820 //inst_cream->S = BIT(inst, 20);
1821 inst_cream->Rn = BITS(inst, 16, 19);
1822 //inst_cream->Rd = BITS(inst, 12, 15);
1823 if (CHECK_RN)
1824 inst_base->load_r15 = 1;
1825 inst_cream->shifter_operand = BITS(inst, 0, 11);
1826 inst_cream->shtop_func = get_shtop(inst);
1827 return inst_base;
1828}
1829ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index)
1830{
1831 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst));
1832 cmp_inst *inst_cream = (cmp_inst *)inst_base->component;
1833
1834 inst_base->cond = BITS(inst, 28, 31);
1835 inst_base->idx = index;
1836 inst_base->br = NON_BRANCH;
1837 inst_base->load_r15 = 0;
1838
1839 inst_cream->I = BIT(inst, 25);
1840 inst_cream->Rn = BITS(inst, 16, 19);
1841 if (CHECK_RN)
1842 inst_base->load_r15 = 1;
1843 inst_cream->shifter_operand = BITS(inst, 0, 11);
1844 inst_cream->shtop_func = get_shtop(inst);
1845 return inst_base;
1846}
1847ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index)
1848{
1849 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst));
1850 cps_inst *inst_cream = (cps_inst *)inst_base->component;
1851
1852 inst_base->cond = BITS(inst, 28, 31);
1853 inst_base->idx = index;
1854 inst_base->br = NON_BRANCH;
1855
1856 inst_cream->imod0 = BIT(inst, 18);
1857 inst_cream->imod1 = BIT(inst, 19);
1858 inst_cream->mmod = BIT(inst, 17);
1859 inst_cream->A = BIT(inst, 8);
1860 inst_cream->I = BIT(inst, 7);
1861 inst_cream->F = BIT(inst, 6);
1862 inst_cream->mode = BITS(inst, 0, 4);
1863
1864 return inst_base;
1865}
1866ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index)
1867{
1868 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
1869 mov_inst *inst_cream = (mov_inst *)inst_base->component;
1870
1871 inst_base->cond = BITS(inst, 28, 31);
1872 inst_base->idx = index;
1873 inst_base->br = NON_BRANCH;
1874
1875 inst_cream->I = BIT(inst, 25);
1876 inst_cream->S = BIT(inst, 20);
1877 inst_cream->Rd = BITS(inst, 12, 15);
1878 inst_cream->shifter_operand = BITS(inst, 0, 11);
1879 inst_cream->shtop_func = get_shtop(inst);
1880
1881 if (inst_cream->Rd == 15) {
1882 inst_base->br = INDIRECT_BRANCH;
1883 }
1884 return inst_base;
1885}
1886ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index)
1887{
1888 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst));
1889 eor_inst *inst_cream = (eor_inst *)inst_base->component;
1890
1891 inst_base->cond = BITS(inst, 28, 31);
1892 inst_base->idx = index;
1893 inst_base->br = NON_BRANCH;
1894 inst_base->load_r15 = 0;
1895
1896 inst_cream->I = BIT(inst, 25);
1897 inst_cream->S = BIT(inst, 20);
1898 inst_cream->Rn = BITS(inst, 16, 19);
1899 inst_cream->Rd = BITS(inst, 12, 15);
1900 if (CHECK_RN)
1901 inst_base->load_r15 = 1;
1902 inst_cream->shifter_operand = BITS(inst, 0, 11);
1903 inst_cream->shtop_func = get_shtop(inst);
1904 if (inst_cream->Rd == 15) {
1905 inst_base->br = INDIRECT_BRANCH;
1906 }
1907 return inst_base;
1908}
1909ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index)
1910{
1911 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst));
1912 inst_base->cond = BITS(inst, 28, 31);
1913 inst_base->idx = index;
1914 inst_base->br = NON_BRANCH;
1915
1916 return inst_base;
1917}
1918ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index)
1919{
1920 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
1921 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
1922
1923 inst_base->cond = BITS(inst, 28, 31);
1924 inst_base->idx = index;
1925 inst_base->br = NON_BRANCH;
1926
1927 inst_cream->inst = inst;
1928 inst_cream->get_addr = get_calc_addr_op(inst);
1929
1930 if (BIT(inst, 15)) {
1931 inst_base->br = INDIRECT_BRANCH;
1932 }
1933 return inst_base;
1934}
1935ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index)
1936{
1937 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
1938 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
1939
1940 inst_base->cond = BITS(inst, 28, 31);
1941 inst_base->idx = index;
1942 inst_base->br = NON_BRANCH;
1943 inst_base->load_r15 = 0;
1944
1945 inst_cream->Rd = BITS(inst, 12, 15);
1946 inst_cream->Rm = BITS(inst, 0, 3);
1947 inst_cream->rotate = BITS(inst, 10, 11);
1948 if (CHECK_RM)
1949 inst_base->load_r15 = 1;
1950
1951 return inst_base;
1952}
1953ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index)
1954{
1955 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
1956 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
1957
1958 inst_base->cond = BITS(inst, 28, 31);
1959 inst_base->idx = index;
1960 inst_base->br = NON_BRANCH;
1961 inst_base->load_r15 = 0;
1962
1963 inst_cream->inst = inst;
1964 inst_cream->get_addr = get_calc_addr_op(inst);
1965
1966 if (BITS(inst, 12, 15) == 15) {
1967 inst_base->br = INDIRECT_BRANCH;
1968 }
1969 return inst_base;
1970}
1971
1972ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index)
1973{
1974 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
1975 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
1976
1977 inst_base->cond = BITS(inst, 28, 31);
1978 inst_base->idx = index;
1979 inst_base->br = NON_BRANCH;
1980 inst_base->load_r15 = 0;
1981
1982 inst_cream->inst = inst;
1983 inst_cream->get_addr = get_calc_addr_op(inst);
1984
1985 if (BITS(inst, 12, 15) == 15) {
1986 inst_base->br = INDIRECT_BRANCH;
1987 }
1988 return inst_base;
1989}
1990
1991ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index)
1992{
1993 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
1994 uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
1995
1996 inst_base->cond = BITS(inst, 28, 31);
1997 inst_base->idx = index;
1998 inst_base->br = NON_BRANCH;
1999 inst_base->load_r15 = 0;
2000
2001 inst_cream->Rd = BITS(inst, 12, 15);
2002 inst_cream->rotate = BITS(inst, 10, 11);
2003 inst_cream->Rm = BITS(inst, 0, 3);
2004 if (CHECK_RM)
2005 inst_base->load_r15 = 1;
2006
2007 return inst_base;
2008}
2009ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index)
2010{
2011 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst));
2012 uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component;
2013
2014 inst_base->cond = BITS(inst, 28, 31);
2015 inst_base->idx = index;
2016 inst_base->br = NON_BRANCH;
2017 inst_base->load_r15 = 0;
2018
2019 inst_cream->Rn = BITS(inst, 16, 19);
2020 inst_cream->Rd = BITS(inst, 12, 15);
2021 inst_cream->rotate = BITS(inst, 10, 11);
2022 inst_cream->Rm = BITS(inst, 0, 3);
2023 if (CHECK_RM || CHECK_RN)
2024 inst_base->load_r15 = 1;
2025
2026 return inst_base;
2027}
2028ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index)
2029{
2030 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2031 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2032
2033 inst_base->cond = BITS(inst, 28, 31);
2034 inst_base->idx = index;
2035 inst_base->br = NON_BRANCH;
2036
2037 inst_cream->inst = inst;
2038 inst_cream->get_addr = get_calc_addr_op(inst);
2039
2040 if (BITS(inst, 12, 15) == 15) {
2041 inst_base->br = INDIRECT_BRANCH;
2042 }
2043 return inst_base;
2044}
2045ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index)
2046{
2047 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2048 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2049
2050 inst_base->cond = BITS(inst, 28, 31);
2051 inst_base->idx = index;
2052 inst_base->br = NON_BRANCH;
2053
2054 inst_cream->inst = inst;
2055 if (I_BIT == 0) {
2056 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
2057 } else {
2058 DEBUG_MSG;
2059 }
2060 #if 0
2061 inst_cream->get_addr = get_calc_addr_op(inst);
2062 if(inst == 0x54f13001) {
2063 DEBUG_LOG(ARM11, "get_calc_addr_op:%llx\n", inst_cream->get_addr);
2064 }
2065 #endif
2066
2067 if (BITS(inst, 12, 15) == 15) {
2068 inst_base->br = INDIRECT_BRANCH;
2069 }
2070 return inst_base;
2071}
2072ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index)
2073{
2074 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2075 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2076
2077 inst_base->cond = BITS(inst, 28, 31);
2078 inst_base->idx = index;
2079 inst_base->br = NON_BRANCH;
2080
2081 inst_cream->inst = inst;
2082 inst_cream->get_addr = get_calc_addr_op(inst);
2083
2084 return inst_base;
2085}
2086
2087ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index)
2088{
2089 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2090 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2091
2092 inst_base->cond = BITS(inst, 28, 31);
2093 inst_base->idx = index;
2094 inst_base->br = NON_BRANCH;
2095
2096 inst_cream->inst = inst;
2097 //inst_cream->get_addr = get_calc_addr_op(inst);
2098
2099 if (BITS(inst, 12, 15) == 15) {
2100 inst_base->br = INDIRECT_BRANCH;
2101 }
2102 return inst_base;
2103}
2104ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index)
2105{
2106 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2107 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2108
2109 inst_base->cond = BITS(inst, 28, 31);
2110 inst_base->idx = index;
2111 inst_base->br = NON_BRANCH;
2112
2113 inst_cream->inst = inst;
2114 inst_cream->get_addr = get_calc_addr_op(inst);
2115
2116 if (BITS(inst, 12, 15) == 15) {
2117 inst_base->br = INDIRECT_BRANCH;
2118 }
2119 return inst_base;
2120}
2121ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index)
2122{
2123 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2124 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2125
2126 inst_base->cond = BITS(inst, 28, 31);
2127 inst_base->idx = index;
2128 inst_base->br = NON_BRANCH;
2129
2130 inst_cream->inst = inst;
2131 inst_cream->get_addr = get_calc_addr_op(inst);
2132
2133 if (BITS(inst, 12, 15) == 15) {
2134 inst_base->br = INDIRECT_BRANCH;
2135 }
2136 return inst_base;
2137}
2138ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index)
2139{
2140 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2141 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2142
2143 inst_base->cond = BITS(inst, 28, 31);
2144 inst_base->idx = index;
2145 inst_base->br = NON_BRANCH;
2146
2147 inst_cream->inst = inst;
2148 inst_cream->get_addr = get_calc_addr_op(inst);
2149
2150 if (BITS(inst, 12, 15) == 15) {
2151 inst_base->br = INDIRECT_BRANCH;
2152 }
2153 return inst_base;
2154}
2155ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index)
2156{
2157 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2158 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2159
2160 inst_base->cond = BITS(inst, 28, 31);
2161 inst_base->idx = index;
2162 inst_base->br = NON_BRANCH;
2163
2164 inst_cream->inst = inst;
2165 inst_cream->get_addr = get_calc_addr_op(inst);
2166
2167 if (BITS(inst, 12, 15) == 15) {
2168 inst_base->br = INDIRECT_BRANCH;
2169 }
2170 return inst_base;
2171}
2172ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index)
2173{
2174 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2175 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2176
2177 inst_base->cond = BITS(inst, 28, 31);
2178 inst_base->idx = index;
2179 inst_base->br = NON_BRANCH;
2180
2181 inst_cream->inst = inst;
2182 if (I_BIT == 0) {
2183 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
2184 } else {
2185 DEBUG_MSG;
2186 }
2187
2188 if (BITS(inst, 12, 15) == 15) {
2189 inst_base->br = INDIRECT_BRANCH;
2190 }
2191 return inst_base;
2192}
2193ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index)
2194{
2195 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst));
2196 mcr_inst *inst_cream = (mcr_inst *)inst_base->component;
2197 inst_base->cond = BITS(inst, 28, 31);
2198 inst_base->idx = index;
2199 inst_base->br = NON_BRANCH;
2200
2201 inst_cream->crn = BITS(inst, 16, 19);
2202 inst_cream->crm = BITS(inst, 0, 3);
2203 inst_cream->opcode_1 = BITS(inst, 21, 23);
2204 inst_cream->opcode_2 = BITS(inst, 5, 7);
2205 inst_cream->Rd = BITS(inst, 12, 15);
2206 inst_cream->cp_num = BITS(inst, 8, 11);
2207 inst_cream->inst = inst;
2208 return inst_base;
2209}
2210ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2211ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index)
2212{
2213 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst));
2214 mla_inst *inst_cream = (mla_inst *)inst_base->component;
2215
2216 inst_base->cond = BITS(inst, 28, 31);
2217 inst_base->idx = index;
2218 inst_base->br = NON_BRANCH;
2219 inst_base->load_r15 = 0;
2220
2221 inst_cream->S = BIT(inst, 20);
2222 inst_cream->Rn = BITS(inst, 12, 15);
2223 inst_cream->Rd = BITS(inst, 16, 19);
2224 inst_cream->Rs = BITS(inst, 8, 11);
2225 inst_cream->Rm = BITS(inst, 0, 3);
2226
2227 if (CHECK_RM || CHECK_RN || CHECK_RS)
2228 inst_base->load_r15 = 1;
2229
2230 return inst_base;
2231}
2232ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index)
2233{
2234 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
2235 mov_inst *inst_cream = (mov_inst *)inst_base->component;
2236
2237 inst_base->cond = BITS(inst, 28, 31);
2238 inst_base->idx = index;
2239 inst_base->br = NON_BRANCH;
2240
2241 inst_cream->I = BIT(inst, 25);
2242 inst_cream->S = BIT(inst, 20);
2243 inst_cream->Rd = BITS(inst, 12, 15);
2244 inst_cream->shifter_operand = BITS(inst, 0, 11);
2245 inst_cream->shtop_func = get_shtop(inst);
2246
2247 if (inst_cream->Rd == 15) {
2248 inst_base->br = INDIRECT_BRANCH;
2249 }
2250 return inst_base;
2251}
2252ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index)
2253{
2254 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst));
2255 mrc_inst *inst_cream = (mrc_inst *)inst_base->component;
2256 inst_base->cond = BITS(inst, 28, 31);
2257 inst_base->idx = index;
2258 inst_base->br = NON_BRANCH;
2259
2260 inst_cream->crn = BITS(inst, 16, 19);
2261 inst_cream->crm = BITS(inst, 0, 3);
2262 inst_cream->opcode_1 = BITS(inst, 21, 23);
2263 inst_cream->opcode_2 = BITS(inst, 5, 7);
2264 inst_cream->Rd = BITS(inst, 12, 15);
2265 inst_cream->cp_num = BITS(inst, 8, 11);
2266 inst_cream->inst = inst;
2267 return inst_base;
2268}
2269ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2270ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index)
2271{
2272 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst));
2273 mrs_inst *inst_cream = (mrs_inst *)inst_base->component;
2274
2275 inst_base->cond = BITS(inst, 28, 31);
2276 inst_base->idx = index;
2277 inst_base->br = NON_BRANCH;
2278
2279 inst_cream->Rd = BITS(inst, 12, 15);
2280 inst_cream->R = BIT(inst, 22);
2281
2282 return inst_base;
2283}
2284ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index)
2285{
2286 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst));
2287 msr_inst *inst_cream = (msr_inst *)inst_base->component;
2288
2289 inst_base->cond = BITS(inst, 28, 31);
2290 inst_base->idx = index;
2291 inst_base->br = NON_BRANCH;
2292
2293 inst_cream->field_mask = BITS(inst, 16, 19);
2294 inst_cream->R = BIT(inst, 22);
2295 inst_cream->inst = inst;
2296
2297 return inst_base;
2298}
2299ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index)
2300{
2301 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst));
2302 mul_inst *inst_cream = (mul_inst *)inst_base->component;
2303
2304 inst_base->cond = BITS(inst, 28, 31);
2305 inst_base->idx = index;
2306 inst_base->br = NON_BRANCH;
2307 inst_base->load_r15 = 0;
2308
2309 inst_cream->S = BIT(inst, 20);
2310 inst_cream->Rm = BITS(inst, 0, 3);
2311 inst_cream->Rs = BITS(inst, 8, 11);
2312 inst_cream->Rd = BITS(inst, 16, 19);
2313
2314 if (CHECK_RM || CHECK_RS)
2315 inst_base->load_r15 = 1;
2316 return inst_base;
2317}
2318ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index)
2319{
2320 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst));
2321 mvn_inst *inst_cream = (mvn_inst *)inst_base->component;
2322
2323 inst_base->cond = BITS(inst, 28, 31);
2324 inst_base->idx = index;
2325 inst_base->br = NON_BRANCH;
2326
2327 inst_cream->I = BIT(inst, 25);
2328 inst_cream->S = BIT(inst, 20);
2329 inst_cream->Rd = BITS(inst, 12, 15);
2330 inst_cream->shifter_operand = BITS(inst, 0, 11);
2331 inst_cream->shtop_func = get_shtop(inst);
2332
2333 if (inst_cream->Rd == 15) {
2334 inst_base->br = INDIRECT_BRANCH;
2335 }
2336 return inst_base;
2337
2338}
2339ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index)
2340{
2341 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst));
2342 orr_inst *inst_cream = (orr_inst *)inst_base->component;
2343
2344 inst_base->cond = BITS(inst, 28, 31);
2345 inst_base->idx = index;
2346 inst_base->br = NON_BRANCH;
2347 inst_base->load_r15 = 0;
2348
2349 inst_cream->I = BIT(inst, 25);
2350 inst_cream->S = BIT(inst, 20);
2351 inst_cream->Rd = BITS(inst, 12, 15);
2352 inst_cream->Rn = BITS(inst, 16, 19);
2353 inst_cream->shifter_operand = BITS(inst, 0, 11);
2354 inst_cream->shtop_func = get_shtop(inst);
2355
2356 if (CHECK_RN)
2357 inst_base->load_r15 = 1;
2358 if (inst_cream->Rd == 15) {
2359 inst_base->br = INDIRECT_BRANCH;
2360 }
2361 return inst_base;
2362}
2363ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2364ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2365ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index)
2366{
2367 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst));
2368
2369 inst_base->cond = BITS(inst, 28, 31);
2370 inst_base->idx = index;
2371 inst_base->br = NON_BRANCH;
2372 inst_base->load_r15 = 0;
2373
2374 return inst_base;
2375}
2376ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2377ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2378ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2379ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2380ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2381ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2382ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2383ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2384ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2385ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2386ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index)
2387{
2388 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
2389 rev_inst *inst_cream = (rev_inst *)inst_base->component;
2390
2391 inst_base->cond = BITS(inst, 28, 31);
2392 inst_base->idx = index;
2393 inst_base->br = NON_BRANCH;
2394 inst_base->load_r15 = 0;
2395
2396 inst_cream->Rm = BITS(inst, 0, 3);
2397 inst_cream->Rd = BITS(inst, 12, 15);
2398
2399 return inst_base;
2400}
2401ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index){
2402 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
2403 rev_inst *inst_cream = (rev_inst *)inst_base->component;
2404
2405 inst_base->cond = BITS(inst, 28, 31);
2406 inst_base->idx = index;
2407 inst_base->br = NON_BRANCH;
2408 inst_base->load_r15 = 0;
2409
2410 inst_cream->Rm = BITS(inst, 0, 3);
2411 inst_cream->Rd = BITS(inst, 12, 15);
2412
2413 return inst_base;
2414}
2415ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2416ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2417ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index)
2418{
2419 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst));
2420 rsb_inst *inst_cream = (rsb_inst *)inst_base->component;
2421
2422 inst_base->cond = BITS(inst, 28, 31);
2423 inst_base->idx = index;
2424 inst_base->br = NON_BRANCH;
2425 inst_base->load_r15 = 0;
2426
2427 inst_cream->I = BIT(inst, 25);
2428 inst_cream->S = BIT(inst, 20);
2429 inst_cream->Rn = BITS(inst, 16, 19);
2430 inst_cream->Rd = BITS(inst, 12, 15);
2431 inst_cream->shifter_operand = BITS(inst, 0, 11);
2432 inst_cream->shtop_func = get_shtop(inst);
2433 if (CHECK_RN)
2434 inst_base->load_r15 = 1;
2435
2436 if (inst_cream->Rd == 15) {
2437 inst_base->br = INDIRECT_BRANCH;
2438 }
2439 return inst_base;
2440}
2441ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index)
2442{
2443 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst));
2444 rsc_inst *inst_cream = (rsc_inst *)inst_base->component;
2445
2446 inst_base->cond = BITS(inst, 28, 31);
2447 inst_base->idx = index;
2448 inst_base->br = NON_BRANCH;
2449 inst_base->load_r15 = 0;
2450
2451 inst_cream->I = BIT(inst, 25);
2452 inst_cream->S = BIT(inst, 20);
2453 inst_cream->Rn = BITS(inst, 16, 19);
2454 inst_cream->Rd = BITS(inst, 12, 15);
2455 inst_cream->shifter_operand = BITS(inst, 0, 11);
2456 inst_cream->shtop_func = get_shtop(inst);
2457 if (CHECK_RN)
2458 inst_base->load_r15 = 1;
2459
2460 if (inst_cream->Rd == 15) {
2461 inst_base->br = INDIRECT_BRANCH;
2462 }
2463 return inst_base;
2464}
2465ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2466ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2467ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2468ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index)
2469{
2470 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst));
2471 sbc_inst *inst_cream = (sbc_inst *)inst_base->component;
2472
2473 inst_base->cond = BITS(inst, 28, 31);
2474 inst_base->idx = index;
2475 inst_base->br = NON_BRANCH;
2476 inst_base->load_r15 = 0;
2477
2478 inst_cream->I = BIT(inst, 25);
2479 inst_cream->S = BIT(inst, 20);
2480 inst_cream->Rn = BITS(inst, 16, 19);
2481 inst_cream->Rd = BITS(inst, 12, 15);
2482 inst_cream->shifter_operand = BITS(inst, 0, 11);
2483 inst_cream->shtop_func = get_shtop(inst);
2484 if (CHECK_RN)
2485 inst_base->load_r15 = 1;
2486
2487 if (inst_cream->Rd == 15) {
2488 inst_base->br = INDIRECT_BRANCH;
2489 }
2490 return inst_base;
2491}
2492ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2493ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2494ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2495ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2496ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2497ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2498ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2499ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2500ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index)
2501{
2502 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst));
2503 smla_inst *inst_cream = (smla_inst *)inst_base->component;
2504
2505 inst_base->cond = BITS(inst, 28, 31);
2506 inst_base->idx = index;
2507 inst_base->br = NON_BRANCH;
2508 inst_base->load_r15 = 0;
2509
2510 inst_cream->x = BIT(inst, 5);
2511 inst_cream->y = BIT(inst, 6);
2512 inst_cream->Rm = BITS(inst, 0, 3);
2513 inst_cream->Rs = BITS(inst, 8, 11);
2514 inst_cream->Rd = BITS(inst, 16, 19);
2515 inst_cream->Rn = BITS(inst, 12, 15);
2516
2517 return inst_base;
2518}
2519ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index){
2520 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
2521 smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
2522
2523 inst_base->cond = BITS(inst, 28, 31);
2524 inst_base->idx = index;
2525 inst_base->br = NON_BRANCH;
2526 inst_base->load_r15 = 0;
2527
2528 inst_cream->m = BIT(inst, 4);
2529 inst_cream->Rn = BITS(inst, 0, 3);
2530 inst_cream->Rm = BITS(inst, 8, 11);
2531 inst_cream->Rd = BITS(inst, 16, 19);
2532 inst_cream->Ra = BITS(inst, 12, 15);
2533
2534 if (CHECK_RM )
2535 inst_base->load_r15 = 1;
2536 return inst_base;
2537}
2538ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index)
2539{
2540 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
2541 umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
2542
2543 inst_base->cond = BITS(inst, 28, 31);
2544 inst_base->idx = index;
2545 inst_base->br = NON_BRANCH;
2546 inst_base->load_r15 = 0;
2547
2548 inst_cream->S = BIT(inst, 20);
2549 inst_cream->Rm = BITS(inst, 0, 3);
2550 inst_cream->Rs = BITS(inst, 8, 11);
2551 inst_cream->RdHi = BITS(inst, 16, 19);
2552 inst_cream->RdLo = BITS(inst, 12, 15);
2553
2554 if (CHECK_RM || CHECK_RS)
2555 inst_base->load_r15 = 1;
2556 return inst_base;
2557}
2558ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2559ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2560ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2561ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2562ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2563ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2564ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2565ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2566ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2567ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index)
2568{
2569 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst));
2570 smul_inst *inst_cream = (smul_inst *)inst_base->component;
2571
2572 inst_base->cond = BITS(inst, 28, 31);
2573 inst_base->idx = index;
2574 inst_base->br = NON_BRANCH;
2575 inst_base->load_r15 = 0;
2576
2577 inst_cream->Rd = BITS(inst, 16, 19);
2578 inst_cream->Rs = BITS(inst, 8, 11);
2579 inst_cream->Rm = BITS(inst, 0, 3);
2580
2581 inst_cream->x = BIT(inst, 5);
2582 inst_cream->y = BIT(inst, 6);
2583
2584 if (CHECK_RM || CHECK_RS)
2585 inst_base->load_r15 = 1;
2586 return inst_base;
2587
2588}
2589ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index)
2590{
2591 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
2592 umull_inst *inst_cream = (umull_inst *)inst_base->component;
2593
2594 inst_base->cond = BITS(inst, 28, 31);
2595 inst_base->idx = index;
2596 inst_base->br = NON_BRANCH;
2597 inst_base->load_r15 = 0;
2598
2599 inst_cream->S = BIT(inst, 20);
2600 inst_cream->Rm = BITS(inst, 0, 3);
2601 inst_cream->Rs = BITS(inst, 8, 11);
2602 inst_cream->RdHi = BITS(inst, 16, 19);
2603 inst_cream->RdLo = BITS(inst, 12, 15);
2604
2605 if (CHECK_RM || CHECK_RS)
2606 inst_base->load_r15 = 1;
2607 return inst_base;
2608}
2609
2610ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index)
2611{
2612 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
2613 smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
2614
2615 inst_base->cond = BITS(inst, 28, 31);
2616 inst_base->idx = index;
2617 inst_base->br = NON_BRANCH;
2618 inst_base->load_r15 = 0;
2619
2620 inst_cream->m = BIT(inst, 6);
2621 inst_cream->Rm = BITS(inst, 8, 11);
2622 inst_cream->Rn = BITS(inst, 0, 3);
2623 inst_cream->Rd = BITS(inst, 16, 19);
2624
2625 if (CHECK_RM || CHECK_RN)
2626 inst_base->load_r15 = 1;
2627 return inst_base;
2628}
2629ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2630ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2631ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2632ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2633ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2634ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2635ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2636ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index)
2637{
2638 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst));
2639 inst_base->cond = BITS(inst, 28, 31);
2640 inst_base->idx = index;
2641 inst_base->br = NON_BRANCH;
2642
2643 return inst_base;
2644}
2645ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index)
2646{
2647 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2648 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2649
2650 inst_base->cond = BITS(inst, 28, 31);
2651 inst_base->idx = index;
2652 inst_base->br = NON_BRANCH;
2653
2654 inst_cream->inst = inst;
2655 inst_cream->get_addr = get_calc_addr_op(inst);
2656 return inst_base;
2657}
2658ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index)
2659{
2660 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
2661 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
2662
2663 inst_base->cond = BITS(inst, 28, 31);
2664 inst_base->idx = index;
2665 inst_base->br = NON_BRANCH;
2666 inst_base->load_r15 = 0;
2667
2668 inst_cream->Rd = BITS(inst, 12, 15);
2669 inst_cream->Rm = BITS(inst, 0, 3);
2670 inst_cream->rotate = BITS(inst, 10, 11);
2671
2672 if (CHECK_RM)
2673 inst_base->load_r15 = 1;
2674 return inst_base;
2675}
2676ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index)
2677{
2678 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2679 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2680
2681 inst_base->cond = BITS(inst, 28, 31);
2682 inst_base->idx = index;
2683 inst_base->br = NON_BRANCH;
2684
2685 inst_cream->inst = inst;
2686 inst_cream->get_addr = get_calc_addr_op(inst);
2687
2688 if (BITS(inst, 12, 15) == 15) {
2689 inst_base->br = INDIRECT_BRANCH;
2690 }
2691 return inst_base;
2692}
2693ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index)
2694{
2695 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
2696 uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
2697
2698 inst_base->cond = BITS(inst, 28, 31);
2699 inst_base->idx = index;
2700 inst_base->br = NON_BRANCH;
2701 inst_base->load_r15 = 0;
2702
2703 inst_cream->Rd = BITS(inst, 12, 15);
2704 inst_cream->rotate = BITS(inst, 10, 11);
2705 inst_cream->Rm = BITS(inst, 0, 3);
2706
2707 if (CHECK_RM)
2708 inst_base->load_r15 = 1;
2709 return inst_base;
2710}
2711ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index)
2712{
2713 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));
2714 uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component;
2715
2716 inst_base->cond = BITS(inst, 28, 31);
2717 inst_base->idx = index;
2718 inst_base->br = NON_BRANCH;
2719 inst_base->load_r15 = 0;
2720
2721 inst_cream->Rd = BITS(inst, 12, 15);
2722 inst_cream->rotate = BITS(inst, 10, 11);
2723 inst_cream->Rm = BITS(inst, 0, 3);
2724 inst_cream->Rn = BITS(inst, 16, 19);
2725
2726 return inst_base;
2727}
2728ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index)
2729{
2730 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2731 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2732
2733 inst_base->cond = BITS(inst, 28, 31);
2734 inst_base->idx = index;
2735 inst_base->br = NON_BRANCH;
2736
2737 inst_cream->inst = inst;
2738 inst_cream->get_addr = get_calc_addr_op(inst);
2739
2740 if (BITS(inst, 12, 15) == 15) {
2741 inst_base->br = INDIRECT_BRANCH;
2742 }
2743 return inst_base;
2744}
2745ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index)
2746{
2747 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2748 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2749
2750 inst_base->cond = BITS(inst, 28, 31);
2751 inst_base->idx = index;
2752 inst_base->br = NON_BRANCH;
2753
2754 inst_cream->inst = inst;
2755// inst_cream->get_addr = get_calc_addr_op(inst);
2756 if (I_BIT == 0) {
2757 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
2758 } else {
2759 DEBUG_MSG;
2760 }
2761
2762 if (BITS(inst, 12, 15) == 15) {
2763 inst_base->br = INDIRECT_BRANCH;
2764 }
2765 return inst_base;
2766}
2767ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){
2768 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2769 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2770
2771 inst_base->cond = BITS(inst, 28, 31);
2772 inst_base->idx = index;
2773 inst_base->br = NON_BRANCH;
2774
2775 inst_cream->inst = inst;
2776 inst_cream->get_addr = get_calc_addr_op(inst);
2777
2778 if (BITS(inst, 12, 15) == 15) {
2779 inst_base->br = INDIRECT_BRANCH;
2780 }
2781 return inst_base;
2782}
2783ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index)
2784{
2785 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2786 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2787
2788 inst_base->cond = BITS(inst, 28, 31);
2789 inst_base->idx = index;
2790 inst_base->br = NON_BRANCH;
2791
2792 inst_cream->inst = inst;
2793 inst_cream->get_addr = get_calc_addr_op(inst);
2794
2795 if (BITS(inst, 12, 15) == 15) {
2796 inst_base->br = INDIRECT_BRANCH;
2797 }
2798 return inst_base;
2799}
2800ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index)
2801{
2802 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2803 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2804
2805 inst_base->cond = BITS(inst, 28, 31);
2806 inst_base->idx = index;
2807 inst_base->br = NON_BRANCH;
2808
2809 inst_cream->inst = inst;
2810 inst_cream->get_addr = get_calc_addr_op(inst);
2811
2812 if (BITS(inst, 12, 15) == 15) {
2813 inst_base->br = INDIRECT_BRANCH;
2814 }
2815 return inst_base;
2816}
2817ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index)
2818{
2819 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2820 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2821
2822 inst_base->cond = BITS(inst, 28, 31);
2823 inst_base->idx = index;
2824 inst_base->br = NON_BRANCH;
2825
2826 inst_cream->inst = inst;
2827 inst_cream->get_addr = get_calc_addr_op(inst);
2828
2829 if (BITS(inst, 12, 15) == 15) {
2830 inst_base->br = INDIRECT_BRANCH;
2831 }
2832 return inst_base;
2833}
2834ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index)
2835{
2836 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2837 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2838
2839 inst_base->cond = BITS(inst, 28, 31);
2840 inst_base->idx = index;
2841 inst_base->br = NON_BRANCH;
2842
2843 inst_cream->inst = inst;
2844 if (I_BIT == 0) {
2845 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
2846 } else {
2847 DEBUG_MSG;
2848 }
2849
2850 if (BITS(inst, 12, 15) == 15) {
2851 inst_base->br = INDIRECT_BRANCH;
2852 }
2853 return inst_base;
2854}
2855ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index)
2856{
2857 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst));
2858 sub_inst *inst_cream = (sub_inst *)inst_base->component;
2859
2860 inst_base->cond = BITS(inst, 28, 31);
2861 inst_base->idx = index;
2862 inst_base->br = NON_BRANCH;
2863 inst_base->load_r15 = 0;
2864
2865 inst_cream->I = BIT(inst, 25);
2866 inst_cream->S = BIT(inst, 20);
2867 inst_cream->Rn = BITS(inst, 16, 19);
2868 inst_cream->Rd = BITS(inst, 12, 15);
2869 inst_cream->shifter_operand = BITS(inst, 0, 11);
2870 inst_cream->shtop_func = get_shtop(inst);
2871 if (inst_cream->Rd == 15) {
2872 inst_base->br = INDIRECT_BRANCH;
2873 }
2874 if (CHECK_RN)
2875 inst_base->load_r15 = 1;
2876
2877 return inst_base;
2878}
2879ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index)
2880{
2881 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst));
2882 swi_inst *inst_cream = (swi_inst *)inst_base->component;
2883
2884 inst_base->cond = BITS(inst, 28, 31);
2885 inst_base->idx = index;
2886 inst_base->br = NON_BRANCH;
2887
2888 inst_cream->num = BITS(inst, 0, 23);
2889 return inst_base;
2890}
2891ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index)
2892{
2893 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
2894 swp_inst *inst_cream = (swp_inst *)inst_base->component;
2895
2896 inst_base->cond = BITS(inst, 28, 31);
2897 inst_base->idx = index;
2898 inst_base->br = NON_BRANCH;
2899
2900 inst_cream->Rn = BITS(inst, 16, 19);
2901 inst_cream->Rd = BITS(inst, 12, 15);
2902 inst_cream->Rm = BITS(inst, 0, 3);
2903
2904 if (inst_cream->Rd == 15) {
2905 inst_base->br = INDIRECT_BRANCH;
2906 }
2907 return inst_base;
2908}
2909ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){
2910 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
2911 swp_inst *inst_cream = (swp_inst *)inst_base->component;
2912
2913 inst_base->cond = BITS(inst, 28, 31);
2914 inst_base->idx = index;
2915 inst_base->br = NON_BRANCH;
2916
2917 inst_cream->Rn = BITS(inst, 16, 19);
2918 inst_cream->Rd = BITS(inst, 12, 15);
2919 inst_cream->Rm = BITS(inst, 0, 3);
2920
2921 if (inst_cream->Rd == 15) {
2922 inst_base->br = INDIRECT_BRANCH;
2923 }
2924 return inst_base;
2925}
2926ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){
2927 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst));
2928 sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component;
2929
2930 inst_base->cond = BITS(inst, 28, 31);
2931 inst_base->idx = index;
2932 inst_base->br = NON_BRANCH;
2933 inst_base->load_r15 = 0;
2934
2935 inst_cream->Rd = BITS(inst, 12, 15);
2936 inst_cream->rotate = BITS(inst, 10, 11);
2937 inst_cream->Rm = BITS(inst, 0, 3);
2938 inst_cream->Rn = BITS(inst, 16, 19);
2939
2940 return inst_base;
2941}
2942ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2943ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index){
2944 DEBUG_LOG(ARM11, "in func %s, SXTAH untested\n", __func__);
2945 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst));
2946 sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component;
2947
2948 inst_base->cond = BITS(inst, 28, 31);
2949 inst_base->idx = index;
2950 inst_base->br = NON_BRANCH;
2951 inst_base->load_r15 = 0;
2952
2953 inst_cream->Rd = BITS(inst, 12, 15);
2954 inst_cream->rotate = BITS(inst, 10, 11);
2955 inst_cream->Rm = BITS(inst, 0, 3);
2956 inst_cream->Rn = BITS(inst, 16, 19);
2957
2958 return inst_base;
2959}
2960ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
2961ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index)
2962{
2963 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst));
2964 teq_inst *inst_cream = (teq_inst *)inst_base->component;
2965
2966 inst_base->cond = BITS(inst, 28, 31);
2967 inst_base->idx = index;
2968 inst_base->br = NON_BRANCH;
2969 inst_base->load_r15 = 0;
2970
2971 inst_cream->I = BIT(inst, 25);
2972 inst_cream->Rn = BITS(inst, 16, 19);
2973 inst_cream->shifter_operand = BITS(inst, 0, 11);
2974 inst_cream->shtop_func = get_shtop(inst);
2975
2976 if (CHECK_RN)
2977 inst_base->load_r15 = 1;
2978 return inst_base;
2979}
2980ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index)
2981{
2982 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst));
2983 tst_inst *inst_cream = (tst_inst *)inst_base->component;
2984
2985 inst_base->cond = BITS(inst, 28, 31);
2986 inst_base->idx = index;
2987 inst_base->br = NON_BRANCH;
2988 inst_base->load_r15 = 0;
2989
2990 inst_cream->I = BIT(inst, 25);
2991 inst_cream->S = BIT(inst, 20);
2992 inst_cream->Rn = BITS(inst, 16, 19);
2993 inst_cream->Rd = BITS(inst, 12, 15);
2994 inst_cream->shifter_operand = BITS(inst, 0, 11);
2995 inst_cream->shtop_func = get_shtop(inst);
2996 if (inst_cream->Rd == 15) {
2997 inst_base->br = INDIRECT_BRANCH;
2998 }
2999
3000 if (CHECK_RN)
3001 inst_base->load_r15 = 1;
3002 return inst_base;
3003}
3004ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3005ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3006ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3007ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3008ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3009ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3010ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3011ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3012ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3013ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3014ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index)
3015{
3016 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
3017 umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
3018
3019 inst_base->cond = BITS(inst, 28, 31);
3020 inst_base->idx = index;
3021 inst_base->br = NON_BRANCH;
3022 inst_base->load_r15 = 0;
3023
3024 inst_cream->S = BIT(inst, 20);
3025 inst_cream->Rm = BITS(inst, 0, 3);
3026 inst_cream->Rs = BITS(inst, 8, 11);
3027 inst_cream->RdHi = BITS(inst, 16, 19);
3028 inst_cream->RdLo = BITS(inst, 12, 15);
3029
3030 if (CHECK_RM || CHECK_RS)
3031 inst_base->load_r15 = 1;
3032 return inst_base;
3033}
3034ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index)
3035{
3036 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
3037 umull_inst *inst_cream = (umull_inst *)inst_base->component;
3038
3039 inst_base->cond = BITS(inst, 28, 31);
3040 inst_base->idx = index;
3041 inst_base->br = NON_BRANCH;
3042 inst_base->load_r15 = 0;
3043
3044 inst_cream->S = BIT(inst, 20);
3045 inst_cream->Rm = BITS(inst, 0, 3);
3046 inst_cream->Rs = BITS(inst, 8, 11);
3047 inst_cream->RdHi = BITS(inst, 16, 19);
3048 inst_cream->RdLo = BITS(inst, 12, 15);
3049
3050 if (CHECK_RM || CHECK_RS)
3051 inst_base->load_r15 = 1;
3052 return inst_base;
3053}
3054
3055ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index)
3056{
3057 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb));
3058 b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component;
3059
3060 inst_cream->imm =((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0);
3061 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
3062 inst_base->idx = index;
3063 inst_base->br = DIRECT_BRANCH;
3064 return inst_base;
3065}
3066
3067ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index)
3068{
3069 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb));
3070 b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component;
3071
3072 inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0));
3073 inst_cream->cond = ((tinst >> 8) & 0xf);
3074 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x, cond=0x%x\n", __FUNCTION__, tinst, inst_cream->imm, inst_cream->cond);
3075 inst_base->idx = index;
3076 inst_base->br = DIRECT_BRANCH;
3077 return inst_base;
3078}
3079
3080ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index)
3081{
3082 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb));
3083 bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component;
3084
3085 inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0));
3086 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
3087
3088 inst_base->idx = index;
3089 inst_base->br = NON_BRANCH;
3090 return inst_base;
3091}
3092ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index)
3093{
3094 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb));
3095 bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component;
3096
3097 inst_cream->imm = (tinst & 0x07FF) << 1;
3098 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
3099 inst_base->idx = index;
3100 inst_base->br = DIRECT_BRANCH;
3101 return inst_base;
3102}
3103ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index)
3104{
3105 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb));
3106 blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component;
3107
3108 inst_cream->imm = (tinst & 0x07FF) << 1;
3109 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
3110 inst_cream->instr = tinst;
3111 inst_base->idx = index;
3112 inst_base->br = DIRECT_BRANCH;
3113 return inst_base;
3114}
3115
3116ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3117ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3118ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3119ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3120ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3121ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3122ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3123ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3124ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3125ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3126ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3127ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3128ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3129ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3130ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;}
3131
3132
3133
3134/* Floating point VFPv3 structures and instructions */
3135
3136#define VFP_INTERPRETER_STRUCT
3137#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3138#undef VFP_INTERPRETER_STRUCT
3139
3140#define VFP_INTERPRETER_TRANS
3141#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3142#undef VFP_INTERPRETER_TRANS
3143
3144
3145
3146typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int);
3147
3148const transop_fp_t arm_instruction_trans[] = {
3149 #define VFP_INTERPRETER_TABLE
3150 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3151 #undef VFP_INTERPRETER_TABLE
3152 INTERPRETER_TRANSLATE(srs),
3153 INTERPRETER_TRANSLATE(rfe),
3154 INTERPRETER_TRANSLATE(bkpt),
3155 INTERPRETER_TRANSLATE(blx),
3156 INTERPRETER_TRANSLATE(cps),
3157 INTERPRETER_TRANSLATE(pld),
3158 INTERPRETER_TRANSLATE(setend),
3159 INTERPRETER_TRANSLATE(clrex),
3160 INTERPRETER_TRANSLATE(rev16),
3161 INTERPRETER_TRANSLATE(usad8),
3162 INTERPRETER_TRANSLATE(sxtb),
3163 INTERPRETER_TRANSLATE(uxtb),
3164 INTERPRETER_TRANSLATE(sxth),
3165 INTERPRETER_TRANSLATE(sxtb16),
3166 INTERPRETER_TRANSLATE(uxth),
3167 INTERPRETER_TRANSLATE(uxtb16),
3168 INTERPRETER_TRANSLATE(cpy),
3169 INTERPRETER_TRANSLATE(uxtab),
3170 INTERPRETER_TRANSLATE(ssub8),
3171 INTERPRETER_TRANSLATE(shsub8),
3172 INTERPRETER_TRANSLATE(ssubaddx),
3173 INTERPRETER_TRANSLATE(strex),
3174 INTERPRETER_TRANSLATE(strexb),
3175 INTERPRETER_TRANSLATE(swp),
3176 INTERPRETER_TRANSLATE(swpb),
3177 INTERPRETER_TRANSLATE(ssub16),
3178 INTERPRETER_TRANSLATE(ssat16),
3179 INTERPRETER_TRANSLATE(shsubaddx),
3180 INTERPRETER_TRANSLATE(qsubaddx),
3181 INTERPRETER_TRANSLATE(shaddsubx),
3182 INTERPRETER_TRANSLATE(shadd8),
3183 INTERPRETER_TRANSLATE(shadd16),
3184 INTERPRETER_TRANSLATE(sel),
3185 INTERPRETER_TRANSLATE(saddsubx),
3186 INTERPRETER_TRANSLATE(sadd8),
3187 INTERPRETER_TRANSLATE(sadd16),
3188 INTERPRETER_TRANSLATE(shsub16),
3189 INTERPRETER_TRANSLATE(umaal),
3190 INTERPRETER_TRANSLATE(uxtab16),
3191 INTERPRETER_TRANSLATE(usubaddx),
3192 INTERPRETER_TRANSLATE(usub8),
3193 INTERPRETER_TRANSLATE(usub16),
3194 INTERPRETER_TRANSLATE(usat16),
3195 INTERPRETER_TRANSLATE(usada8),
3196 INTERPRETER_TRANSLATE(uqsubaddx),
3197 INTERPRETER_TRANSLATE(uqsub8),
3198 INTERPRETER_TRANSLATE(uqsub16),
3199 INTERPRETER_TRANSLATE(uqaddsubx),
3200 INTERPRETER_TRANSLATE(uqadd8),
3201 INTERPRETER_TRANSLATE(uqadd16),
3202 INTERPRETER_TRANSLATE(sxtab),
3203 INTERPRETER_TRANSLATE(uhsubaddx),
3204 INTERPRETER_TRANSLATE(uhsub8),
3205 INTERPRETER_TRANSLATE(uhsub16),
3206 INTERPRETER_TRANSLATE(uhaddsubx),
3207 INTERPRETER_TRANSLATE(uhadd8),
3208 INTERPRETER_TRANSLATE(uhadd16),
3209 INTERPRETER_TRANSLATE(uaddsubx),
3210 INTERPRETER_TRANSLATE(uadd8),
3211 INTERPRETER_TRANSLATE(uadd16),
3212 INTERPRETER_TRANSLATE(sxtah),
3213 INTERPRETER_TRANSLATE(sxtab16),
3214 INTERPRETER_TRANSLATE(qadd8),
3215 INTERPRETER_TRANSLATE(bxj),
3216 INTERPRETER_TRANSLATE(clz),
3217 INTERPRETER_TRANSLATE(uxtah),
3218 INTERPRETER_TRANSLATE(bx),
3219 INTERPRETER_TRANSLATE(rev),
3220 INTERPRETER_TRANSLATE(blx),
3221 INTERPRETER_TRANSLATE(revsh),
3222 INTERPRETER_TRANSLATE(qadd),
3223 INTERPRETER_TRANSLATE(qadd16),
3224 INTERPRETER_TRANSLATE(qaddsubx),
3225 INTERPRETER_TRANSLATE(ldrex),
3226 INTERPRETER_TRANSLATE(qdadd),
3227 INTERPRETER_TRANSLATE(qdsub),
3228 INTERPRETER_TRANSLATE(qsub),
3229 INTERPRETER_TRANSLATE(ldrexb),
3230 INTERPRETER_TRANSLATE(qsub8),
3231 INTERPRETER_TRANSLATE(qsub16),
3232 INTERPRETER_TRANSLATE(smuad),
3233 INTERPRETER_TRANSLATE(smmul),
3234 INTERPRETER_TRANSLATE(smusd),
3235 INTERPRETER_TRANSLATE(smlsd),
3236 INTERPRETER_TRANSLATE(smlsld),
3237 INTERPRETER_TRANSLATE(smmla),
3238 INTERPRETER_TRANSLATE(smmls),
3239 INTERPRETER_TRANSLATE(smlald),
3240 INTERPRETER_TRANSLATE(smlad),
3241 INTERPRETER_TRANSLATE(smlaw),
3242 INTERPRETER_TRANSLATE(smulw),
3243 INTERPRETER_TRANSLATE(pkhtb),
3244 INTERPRETER_TRANSLATE(pkhbt),
3245 INTERPRETER_TRANSLATE(smul),
3246 INTERPRETER_TRANSLATE(smlalxy),
3247 INTERPRETER_TRANSLATE(smla),
3248 INTERPRETER_TRANSLATE(mcrr),
3249 INTERPRETER_TRANSLATE(mrrc),
3250 INTERPRETER_TRANSLATE(cmp),
3251 INTERPRETER_TRANSLATE(tst),
3252 INTERPRETER_TRANSLATE(teq),
3253 INTERPRETER_TRANSLATE(cmn),
3254 INTERPRETER_TRANSLATE(smull),
3255 INTERPRETER_TRANSLATE(umull),
3256 INTERPRETER_TRANSLATE(umlal),
3257 INTERPRETER_TRANSLATE(smlal),
3258 INTERPRETER_TRANSLATE(mul),
3259 INTERPRETER_TRANSLATE(mla),
3260 INTERPRETER_TRANSLATE(ssat),
3261 INTERPRETER_TRANSLATE(usat),
3262 INTERPRETER_TRANSLATE(mrs),
3263 INTERPRETER_TRANSLATE(msr),
3264 INTERPRETER_TRANSLATE(and),
3265 INTERPRETER_TRANSLATE(bic),
3266 INTERPRETER_TRANSLATE(ldm),
3267 INTERPRETER_TRANSLATE(eor),
3268 INTERPRETER_TRANSLATE(add),
3269 INTERPRETER_TRANSLATE(rsb),
3270 INTERPRETER_TRANSLATE(rsc),
3271 INTERPRETER_TRANSLATE(sbc),
3272 INTERPRETER_TRANSLATE(adc),
3273 INTERPRETER_TRANSLATE(sub),
3274 INTERPRETER_TRANSLATE(orr),
3275 INTERPRETER_TRANSLATE(mvn),
3276 INTERPRETER_TRANSLATE(mov),
3277 INTERPRETER_TRANSLATE(stm),
3278 INTERPRETER_TRANSLATE(ldm),
3279 INTERPRETER_TRANSLATE(ldrsh),
3280 INTERPRETER_TRANSLATE(stm),
3281 INTERPRETER_TRANSLATE(ldm),
3282 INTERPRETER_TRANSLATE(ldrsb),
3283 INTERPRETER_TRANSLATE(strd),
3284 INTERPRETER_TRANSLATE(ldrh),
3285 INTERPRETER_TRANSLATE(strh),
3286 INTERPRETER_TRANSLATE(ldrd),
3287 INTERPRETER_TRANSLATE(strt),
3288 INTERPRETER_TRANSLATE(strbt),
3289 INTERPRETER_TRANSLATE(ldrbt),
3290 INTERPRETER_TRANSLATE(ldrt),
3291 INTERPRETER_TRANSLATE(mrc),
3292 INTERPRETER_TRANSLATE(mcr),
3293 INTERPRETER_TRANSLATE(msr),
3294 INTERPRETER_TRANSLATE(ldrb),
3295 INTERPRETER_TRANSLATE(strb),
3296 INTERPRETER_TRANSLATE(ldr),
3297 INTERPRETER_TRANSLATE(ldrcond),
3298 INTERPRETER_TRANSLATE(str),
3299 INTERPRETER_TRANSLATE(cdp),
3300 INTERPRETER_TRANSLATE(stc),
3301 INTERPRETER_TRANSLATE(ldc),
3302 INTERPRETER_TRANSLATE(swi),
3303 INTERPRETER_TRANSLATE(bbl),
3304 /* All the thumb instructions should be placed the end of table */
3305 INTERPRETER_TRANSLATE(b_2_thumb),
3306 INTERPRETER_TRANSLATE(b_cond_thumb),
3307 INTERPRETER_TRANSLATE(bl_1_thumb),
3308 INTERPRETER_TRANSLATE(bl_2_thumb),
3309 INTERPRETER_TRANSLATE(blx_1_thumb)
3310};
3311
3312typedef map<unsigned int, int> bb_map;
3313bb_map CreamCache[65536];
3314bb_map ProfileCache[65536];
3315
3316//#define USE_DUMMY_CACHE
3317
3318#ifdef USE_DUMMY_CACHE
3319unsigned int DummyCache[0x100000];
3320#endif
3321
3322#define HASH(x) ((x + (x << 3) + (x >> 6)) % 65536)
3323void insert_bb(unsigned int addr, int start)
3324{
3325#ifdef USE_DUMMY_CACHE
3326 DummyCache[addr] = start;
3327#else
3328// CreamCache[addr] = start;
3329 CreamCache[HASH(addr)][addr] = start;
3330#endif
3331}
3332
3333#define TRANS_THRESHOLD 65000
3334int find_bb(unsigned int addr, int &start)
3335{
3336 int ret = -1;
3337#ifdef USE_DUMMY_CACHE
3338 start = DummyCache[addr];
3339 if (start) {
3340 ret = 0;
3341 } else
3342 ret = -1;
3343#else
3344 bb_map::const_iterator it = CreamCache[HASH(addr)].find(addr);
3345 if (it != CreamCache[HASH(addr)].end()) {
3346 start = static_cast<int>(it->second);
3347 ret = 0;
3348#if HYBRID_MODE
3349#if PROFILE
3350#else
3351 /* increase the bb counter */
3352 if(get_bb_prof(cpu, addr, 1) == TRANS_THRESHOLD){
3353 push_to_compiled(cpu, addr);
3354 }
3355#endif
3356#endif
3357 } else {
3358 ret = -1;
3359 }
3360#endif
3361 return ret;
3362}
3363
3364
3365enum {
3366 FETCH_SUCCESS,
3367 FETCH_FAILURE
3368};
3369static 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){
3370 /* Check if in Thumb mode. */
3371 tdstate ret;
3372 ret = thumb_translate (addr, inst, arm_inst, inst_size);
3373 if(ret == t_branch){
3374 /* FIXME, endian should be judged */
3375 uint32 tinstr;
3376 if((addr & 0x3) != 0)
3377 tinstr = inst >> 16;
3378 else
3379 tinstr = inst & 0xFFFF;
3380
3381 //tinstr = inst & 0xFFFF;
3382 int inst_index;
3383 /* table_length */
3384 int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t);
3385
3386 switch((tinstr & 0xF800) >> 11){
3387 /* we will translate the thumb instruction directly here */
3388 /* we will translate the thumb instruction directly here */
3389 case 26:
3390 case 27:
3391 if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){
3392 uint32 cond = (tinstr & 0x0F00) >> 8;
3393 inst_index = table_length - 4;
3394 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index);
3395 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3396 }
3397 else{
3398 /* something wrong */
3399 DEBUG_LOG(ARM11, "In %s, thumb decoder error\n", __FUNCTION__);
3400 }
3401 break;
3402 case 28:
3403 /* Branch 2, unconditional branch */
3404 inst_index = table_length - 5;
3405 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index);
3406 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3407 break;
3408
3409 case 8:
3410 case 29:
3411 /* For BLX 1 thumb instruction*/
3412 inst_index = table_length - 1;
3413 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc);
3414 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3415 break;
3416 case 30:
3417 /* For BL 1 thumb instruction*/
3418 inst_index = table_length - 3;
3419 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc);
3420 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3421 break;
3422 case 31:
3423 /* For BL 2 thumb instruction*/
3424 inst_index = table_length - 2;
3425 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 2 thumb index=%d, px=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc);
3426 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3427 break;
3428 default:
3429 ret = t_undefined;
3430 break;
3431 }
3432 }
3433 return ret;
3434}
3435
3436#if 0
3437int FetchInst(cpu_t *core, unsigned int &inst)
3438{
3439 //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
3440 arm_processor *cpu = (arm_processor *)(core->cpu_data->obj);
3441// fault_t fault = interpreter_read_memory(cpu->translate_pc, inst, 32);
3442 fault_t fault = interpreter_fetch(core, cpu->translate_pc, inst, 32);
3443 if (!core->is_user_mode) {
3444 if (fault) {
3445 cpu->abortSig = true;
3446 cpu->Aborted = ARMul_PrefetchAbortV;
3447 cpu->AbortAddr = cpu->translate_pc;
3448 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
3449 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->translate_pc;
3450 return FETCH_FAILURE;
3451 }
3452 }
3453 return FETCH_SUCCESS;
3454}
3455#endif
3456
3457unsigned int *InstLength;
3458
3459enum {
3460 KEEP_GOING,
3461 FETCH_EXCEPTION
3462};
3463
3464typedef struct instruction_set_encoding_item ISEITEM;
3465
3466extern const ISEITEM arm_instruction[];
3467
3468vector<uint64_t> code_page_set;
3469
3470void flush_bb(uint32_t addr)
3471{
3472 bb_map::iterator it;
3473 uint32_t start;
3474
3475 addr &= 0xfffff000;
3476 for (int i = 0; i < 65536; i ++) {
3477 for (it = CreamCache[i].begin(); it != CreamCache[i].end(); ) {
3478 start = static_cast<uint32_t>(it->first);
3479 //start = (start >> 12) << 12;
3480 start &= 0xfffff000;
3481 if (start == addr) {
3482 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
3483 CreamCache[i].erase(it ++);
3484 } else
3485 ++it;
3486 }
3487 }
3488
3489 for (int i = 0; i < 65536; i ++) {
3490 for (it = ProfileCache[i].begin(); it != ProfileCache[i].end(); ) {
3491 start = static_cast<uint32_t>(it->first);
3492 //start = (start >> 12) << 12;
3493 start &= 0xfffff000;
3494 if (start == addr) {
3495 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
3496 ProfileCache[i].erase(it ++);
3497 } else
3498 ++it;
3499 }
3500 }
3501
3502 //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr);
3503}
3504
3505//static uint32_t get_bank_addr(void *addr)
3506//{
3507// uint64_t address = (uint64_t)addr;
3508// uint64_t bank0 = get_dma_addr(BANK0_START);
3509// if ((address >= bank0) && (address < (bank0 + BANK0_SIZE))) {
3510// //DEBUG_LOG(ARM11, "1.addr is %llx\n", addr);
3511// return ((uint64_t)addr - bank0) + BANK0_START;
3512// }
3513// return 0;
3514//}
3515
3516/* shenoubang add win32 2012-6-12 */
3517//#ifndef __WIN32__
3518//static void flush_code_cache(int signal_number, siginfo_t *si, void *unused)
3519//{
3520// DEBUG_LOG(ARM11, "in %s, addr=0x%llx\n", __FUNCTION__, si->si_addr);
3521// uint64_t addr = (uint64_t)si->si_addr;
3522// addr = (addr >> 12) << 12;
3523// skyeye_backtrace();
3524// #if 0
3525// if (addr == 0) {
3526// return;
3527// }
3528// const vector<uint64_t>::iterator it = find(code_page_set.begin(),
3529// code_page_set.end(),
3530// (uint64_t)addr);
3531// if (it != code_page_set.end()) {
3532// code_page_set.erase(it);
3533// }
3534// mprotect((void *)addr, 4096, PROT_READ | PROT_WRITE);
3535// //DEBUG_LOG(ARM11, "[flush][ADDR:0x%08llx]\n", addr);
3536// uint32_t phys_addr = get_bank_addr((void *)addr);
3537//// DEBUG_LOG(ARM11, "[PHYSICAL][ADDR:0x%08llx]\n", phys_addr);
3538// flush_bb(phys_addr);
3539// flush_bb(phys_addr + 4096);
3540//#if HYBRID_MODE
3541// /* flush the translated BB of dyncom */
3542// clear_translated_cache(phys_addr);
3543//#endif
3544// #endif
3545//}
3546//#endif /* shenoubang */
3547
3548//void protect_code_page(uint32_t addr)
3549//{
3550// void *mem_ptr = (void *)get_dma_addr(addr);
3551// mem_ptr = (void *)((long long int)mem_ptr & 0xfffffffffffff000LL);
3552//
3553// const vector<uint64_t>::iterator it = find(code_page_set.begin(),
3554// code_page_set.end(),
3555// (uint64_t)mem_ptr);
3556// if (it != code_page_set.end()) {
3557// return;
3558// }
3559// //DEBUG_LOG(ARM11, "[mprotect][ADDR:0x%08llx]\n", mem_ptr);
3560// /* shenoubang add win32 2012-6-12 */
3561//#ifndef __WIN32__
3562// struct sigaction sa;
3563//
3564// memset(&sa, 0, sizeof(sa));
3565// sa.sa_flags = SA_RESTART | SA_SIGINFO;
3566// sa.sa_sigaction = &flush_code_cache;
3567// sigaction(SIGSEGV, &sa, NULL);
3568//
3569// //mprotect(mem_ptr, 4096, PROT_READ);
3570//
3571// code_page_set.push_back((uint64_t)mem_ptr);
3572//#endif /* shenoubang */
3573//}
3574
3575
3576
3577int InterpreterTranslate(arm_processor *cpu, int &bb_start, addr_t addr)
3578{
3579 /* Decode instruction, get index */
3580 /* Allocate memory and init InsCream */
3581 /* Go on next, until terminal instruction */
3582 /* Save start addr of basicblock in CreamCache */
3583 //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
3584 //arm_processor *cpu = (arm_processor *)(core->cpu_data->obj);
3585 ARM_INST_PTR inst_base = NULL;
3586 unsigned int inst, inst_size = 4;
3587 int idx;
3588 int ret = NON_BRANCH;
3589 int thumb = 0;
3590 /* instruction size of basic block */
3591 int size = 0;
3592 /* (R15 - 8) ? */
3593 //cpu->translate_pc = cpu->Reg[15];
3594 bb_start = top;
3595
3596 if (cpu->TFlag)
3597 thumb = THUMB;
3598
3599 addr_t phys_addr;
3600 addr_t pc_start;
3601 fault_t fault = NO_FAULT;
3602 //fault = check_address_validity(cpu, addr, &phys_addr, 1, INSN_TLB);
3603 fault = check_address_validity(cpu, addr, &phys_addr, 1);
3604 if(fault != NO_FAULT){
3605 cpu->abortSig = true;
3606 cpu->Aborted = ARMul_PrefetchAbortV;
3607 cpu->AbortAddr = addr;
3608 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
3609 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
3610 return FETCH_EXCEPTION;
3611 }
3612 pc_start = phys_addr;
3613 //phys_addr = get_dma_addr(phys_addr);
3614 while(ret == NON_BRANCH) {
3615 /* shenoubang add win32 2012-6-14 */
3616#ifdef __WIN32__
3617 mem_bank_t* bank;
3618 if (bank = bank_ptr(addr)) {
3619 bank->bank_read(32, phys_addr, &inst);
3620 }
3621 else {
3622 DEBUG_LOG(ARM11, "SKYEYE: Read physical addr 0x%x error!!\n", phys_addr);
3623 return FETCH_FAILURE;
3624 }
3625#else
3626 inst = Memory::Read32(phys_addr & 0xFFFFFFFC);//*(uint32_t *)(phys_addr & 0xFFFFFFFC);
3627#endif
3628 //or_tag(core, phys_addr, TAG_FAST_INTERP);
3629
3630 /*if (ret == FETCH_FAILURE) {
3631 return FETCH_EXCEPTION;
3632 }*/
3633
3634 size ++;
3635 /* If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction */
3636 if (cpu->TFlag){
3637 //if(cpu->Cpsr & (1 << THUMB_BIT)){
3638 uint32_t arm_inst;
3639 tdstate state;
3640 state = decode_thumb_instr(cpu, inst, phys_addr, &arm_inst, &inst_size, &inst_base);
3641 //or_tag(core, phys_addr, TAG_THUMB);
3642 //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);
3643 /* we have translated the branch instruction of thumb in thumb decoder */
3644 if(state == t_branch){
3645 goto translated;
3646 }
3647 inst = arm_inst;
3648 }
3649
3650 ret = decode_arm_instr(inst, &idx);
3651 if (ret == DECODE_FAILURE) {
3652 DEBUG_LOG(ARM11, "[info] : Decode failure.\tPC : [0x%x]\tInstruction : [%x]\n", phys_addr, inst);
3653 DEBUG_LOG(ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x\n", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]);
3654 CITRA_IGNORE_EXIT(-1);
3655 }
3656// DEBUG_LOG(ARM11, "PC : [0x%x] INST : %s\n", cpu->translate_pc, arm_instruction[idx].name);
3657 inst_base = arm_instruction_trans[idx](inst, idx);
3658// DEBUG_LOG(ARM11, "translated @ %x INST : %x\n", cpu->translate_pc, inst);
3659// DEBUG_LOG(ARM11, "inst size is %d\n", InstLength[idx]);
3660translated:
3661 phys_addr += inst_size;
3662
3663 if ((phys_addr & 0xfff) == 0) {
3664 inst_base->br = END_OF_PAGE;
3665 }
3666 ret = inst_base->br;
3667 };
3668
3669 //DEBUG_LOG(ARM11, "In %s,insert_bb pc=0x%x, TFlag=0x%x\n", __FUNCTION__, pc_start, cpu->TFlag);
3670 insert_bb(pc_start, bb_start);
3671 return KEEP_GOING;
3672}
3673
3674#define LOG_IN_CLR skyeye_printf_in_color
3675
3676int cmp(const void *x, const void *y)
3677{
3678 return *(unsigned long long int*)x - *(unsigned long long int *)y;
3679}
3680
3681void InterpreterInitInstLength(unsigned long long int *ptr, size_t size)
3682{
3683 int array_size = size / sizeof(void *);
3684 unsigned long long int *InstLabel = new unsigned long long int[array_size];
3685 memcpy(InstLabel, ptr, size);
3686 qsort(InstLabel, array_size, sizeof(void *), cmp);
3687 InstLength = new unsigned int[array_size - 4];
3688 for (int i = 0; i < array_size - 4; i ++) {
3689 for (int j = 0; j < array_size; j ++) {
3690 if (ptr[i] == InstLabel[j]) {
3691 InstLength[i] = InstLabel[j + 1] - InstLabel[j];
3692 break;
3693 }
3694 }
3695 }
3696 for (int i = 0; i < array_size - 4; i ++)
3697 DEBUG_LOG(ARM11, "[%d]:%d\n", i, InstLength[i]);
3698}
3699
3700int clz(unsigned int x)
3701{
3702 int n;
3703 if (x == 0) return (32);
3704 n = 1;
3705 if ((x >> 16) == 0) { n = n + 16; x = x << 16;}
3706 if ((x >> 24) == 0) { n = n + 8; x = x << 8;}
3707 if ((x >> 28) == 0) { n = n + 4; x = x << 4;}
3708 if ((x >> 30) == 0) { n = n + 2; x = x << 2;}
3709 n = n - (x >> 31);
3710 return n;
3711}
3712
3713unsigned arm_dyncom_SWI (ARMul_State * state, ARMword number);
3714
3715static bool InAPrivilegedMode(arm_core_t *core)
3716{
3717 return (core->Mode != USER32MODE);
3718}
3719
3720/* r15 = r15 + 8 */
3721unsigned InterpreterMainLoop(ARMul_State* state)
3722{
3723 #define CRn inst_cream->crn
3724 #define OPCODE_2 inst_cream->opcode_2
3725 #define CRm inst_cream->crm
3726 #define CP15_REG(n) cpu->CP15[CP15(n)]
3727 #define RD cpu->Reg[inst_cream->Rd]
3728 #define RN cpu->Reg[inst_cream->Rn]
3729 #define RM cpu->Reg[inst_cream->Rm]
3730 #define RS cpu->Reg[inst_cream->Rs]
3731 #define RDHI cpu->Reg[inst_cream->RdHi]
3732 #define RDLO cpu->Reg[inst_cream->RdLo]
3733 #define LINK_RTN_ADDR (cpu->Reg[14] = cpu->Reg[15] + 4)
3734 #define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24)
3735 #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand)
3736
3737 #if ENABLE_ICOUNTER
3738 #define INC_ICOUNTER cpu->icounter++; \
3739 if(cpu->Reg[15] > 0xc0000000) \
3740 cpu->kernel_icounter++;
3741 //if (debug_function(core)) \
3742 if (core->check_int_flag) \
3743 goto END
3744 //DEBUG_LOG(ARM11, "icounter is %llx line is %d pc is %x\n", cpu->icounter, __LINE__, cpu->Reg[15])
3745 #else
3746 #define INC_ICOUNTER ;
3747 #endif
3748
3749 #define FETCH_INST if (inst_base->br != NON_BRANCH) \
3750 goto DISPATCH; \
3751 inst_base = (arm_inst *)&inst_buf[ptr]
3752#define INC_PC(l) ptr += sizeof(arm_inst) + l
3753
3754// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
3755// clunky switch statement.
3756#if defined __GNUC__ || defined __clang__
3757#define GOTO_NEXT_INST \
3758 if (num_instrs >= cpu->NumInstrsToExecute) goto END; \
3759 num_instrs++; \
3760 goto *InstLabel[inst_base->idx]
3761#else
3762#define GOTO_NEXT_INST \
3763 if (num_instrs >= cpu->NumInstrsToExecute) goto END; \
3764 num_instrs++; \
3765 switch(inst_base->idx) { \
3766 case 0: goto VMLA_INST; \
3767 case 1: goto VMLS_INST; \
3768 case 2: goto VNMLA_INST; \
3769 case 3: goto VNMLA_INST; \
3770 case 4: goto VNMLS_INST; \
3771 case 5: goto VNMUL_INST; \
3772 case 6: goto VMUL_INST; \
3773 case 7: goto VADD_INST; \
3774 case 8: goto VSUB_INST; \
3775 case 9: goto VDIV_INST; \
3776 case 10: goto VMOVI_INST; \
3777 case 11: goto VMOVR_INST; \
3778 case 12: goto VABS_INST; \
3779 case 13: goto VNEG_INST; \
3780 case 14: goto VSQRT_INST; \
3781 case 15: goto VCMP_INST; \
3782 case 16: goto VCMP2_INST; \
3783 case 17: goto VCVTBDS_INST; \
3784 case 18: goto VCVTBFF_INST; \
3785 case 19: goto VCVTBFI_INST; \
3786 case 20: goto VMOVBRS_INST; \
3787 case 21: goto VMSR_INST; \
3788 case 22: goto VMOVBRC_INST; \
3789 case 23: goto VMRS_INST; \
3790 case 24: goto VMOVBCR_INST; \
3791 case 25: goto VMOVBRRSS_INST; \
3792 case 26: goto VMOVBRRD_INST; \
3793 case 27: goto VSTR_INST; \
3794 case 28: goto VPUSH_INST; \
3795 case 29: goto VSTM_INST; \
3796 case 30: goto VPOP_INST; \
3797 case 31: goto VLDR_INST; \
3798 case 32: goto VLDM_INST ; \
3799 case 33: goto SRS_INST; \
3800 case 34: goto RFE_INST; \
3801 case 35: goto BKPT_INST; \
3802 case 36: goto BLX_INST; \
3803 case 37: goto CPS_INST; \
3804 case 38: goto PLD_INST; \
3805 case 39: goto SETEND_INST; \
3806 case 40: goto CLREX_INST; \
3807 case 41: goto REV16_INST; \
3808 case 42: goto USAD8_INST; \
3809 case 43: goto SXTB_INST; \
3810 case 44: goto UXTB_INST; \
3811 case 45: goto SXTH_INST; \
3812 case 46: goto SXTB16_INST; \
3813 case 47: goto UXTH_INST; \
3814 case 48: goto UXTB16_INST; \
3815 case 49: goto CPY_INST; \
3816 case 50: goto UXTAB_INST; \
3817 case 51: goto SSUB8_INST; \
3818 case 52: goto SHSUB8_INST; \
3819 case 53: goto SSUBADDX_INST; \
3820 case 54: goto STREX_INST; \
3821 case 55: goto STREXB_INST; \
3822 case 56: goto SWP_INST; \
3823 case 57: goto SWPB_INST; \
3824 case 58: goto SSUB16_INST; \
3825 case 59: goto SSAT16_INST; \
3826 case 60: goto SHSUBADDX_INST; \
3827 case 61: goto QSUBADDX_INST; \
3828 case 62: goto SHADDSUBX_INST; \
3829 case 63: goto SHADD8_INST; \
3830 case 64: goto SHADD16_INST; \
3831 case 65: goto SEL_INST; \
3832 case 66: goto SADDSUBX_INST; \
3833 case 67: goto SADD8_INST; \
3834 case 68: goto SADD16_INST; \
3835 case 69: goto SHSUB16_INST; \
3836 case 70: goto UMAAL_INST; \
3837 case 71: goto UXTAB16_INST; \
3838 case 72: goto USUBADDX_INST; \
3839 case 73: goto USUB8_INST; \
3840 case 74: goto USUB16_INST; \
3841 case 75: goto USAT16_INST; \
3842 case 76: goto USADA8_INST; \
3843 case 77: goto UQSUBADDX_INST; \
3844 case 78: goto UQSUB8_INST; \
3845 case 79: goto UQSUB16_INST; \
3846 case 80: goto UQADDSUBX_INST; \
3847 case 81: goto UQADD8_INST; \
3848 case 82: goto UQADD16_INST; \
3849 case 83: goto SXTAB_INST; \
3850 case 84: goto UHSUBADDX_INST; \
3851 case 85: goto UHSUB8_INST; \
3852 case 86: goto UHSUB16_INST; \
3853 case 87: goto UHADDSUBX_INST; \
3854 case 88: goto UHADD8_INST; \
3855 case 89: goto UHADD16_INST; \
3856 case 90: goto UADDSUBX_INST; \
3857 case 91: goto UADD8_INST; \
3858 case 92: goto UADD16_INST; \
3859 case 93: goto SXTAH_INST; \
3860 case 94: goto SXTAB16_INST; \
3861 case 95: goto QADD8_INST; \
3862 case 96: goto BXJ_INST; \
3863 case 97: goto CLZ_INST; \
3864 case 98: goto UXTAH_INST; \
3865 case 99: goto BX_INST; \
3866 case 100: goto REV_INST; \
3867 case 101: goto BLX_INST; \
3868 case 102: goto REVSH_INST; \
3869 case 103: goto QADD_INST; \
3870 case 104: goto QADD16_INST; \
3871 case 105: goto QADDSUBX_INST; \
3872 case 106: goto LDREX_INST; \
3873 case 107: goto QDADD_INST; \
3874 case 108: goto QDSUB_INST; \
3875 case 109: goto QSUB_INST; \
3876 case 110: goto LDREXB_INST; \
3877 case 111: goto QSUB8_INST; \
3878 case 112: goto QSUB16_INST; \
3879 case 113: goto SMUAD_INST; \
3880 case 114: goto SMMUL_INST; \
3881 case 115: goto SMUSD_INST; \
3882 case 116: goto SMLSD_INST; \
3883 case 117: goto SMLSLD_INST; \
3884 case 118: goto SMMLA_INST; \
3885 case 119: goto SMMLS_INST; \
3886 case 120: goto SMLALD_INST; \
3887 case 121: goto SMLAD_INST; \
3888 case 122: goto SMLAW_INST; \
3889 case 123: goto SMULW_INST; \
3890 case 124: goto PKHTB_INST; \
3891 case 125: goto PKHBT_INST; \
3892 case 126: goto SMUL_INST; \
3893 case 127: goto SMLAL_INST; \
3894 case 128: goto SMLA_INST; \
3895 case 129: goto MCRR_INST; \
3896 case 130: goto MRRC_INST; \
3897 case 131: goto CMP_INST; \
3898 case 132: goto TST_INST; \
3899 case 133: goto TEQ_INST; \
3900 case 134: goto CMN_INST; \
3901 case 135: goto SMULL_INST; \
3902 case 136: goto UMULL_INST; \
3903 case 137: goto UMLAL_INST; \
3904 case 138: goto SMLAL_INST; \
3905 case 139: goto MUL_INST; \
3906 case 140: goto MLA_INST; \
3907 case 141: goto SSAT_INST; \
3908 case 142: goto USAT_INST; \
3909 case 143: goto MRS_INST; \
3910 case 144: goto MSR_INST; \
3911 case 145: goto AND_INST; \
3912 case 146: goto BIC_INST; \
3913 case 147: goto LDM_INST; \
3914 case 148: goto EOR_INST; \
3915 case 149: goto ADD_INST; \
3916 case 150: goto RSB_INST; \
3917 case 151: goto RSC_INST; \
3918 case 152: goto SBC_INST; \
3919 case 153: goto ADC_INST; \
3920 case 154: goto SUB_INST; \
3921 case 155: goto ORR_INST; \
3922 case 156: goto MVN_INST; \
3923 case 157: goto MOV_INST; \
3924 case 158: goto STM_INST; \
3925 case 159: goto LDM_INST; \
3926 case 160: goto LDRSH_INST; \
3927 case 161: goto STM_INST; \
3928 case 162: goto LDM_INST; \
3929 case 163: goto LDRSB_INST; \
3930 case 164: goto STRD_INST; \
3931 case 165: goto LDRH_INST; \
3932 case 166: goto STRH_INST; \
3933 case 167: goto LDRD_INST; \
3934 case 168: goto STRT_INST; \
3935 case 169: goto STRBT_INST; \
3936 case 170: goto LDRBT_INST; \
3937 case 171: goto LDRT_INST; \
3938 case 172: goto MRC_INST; \
3939 case 173: goto MCR_INST; \
3940 case 174: goto MSR_INST; \
3941 case 175: goto LDRB_INST; \
3942 case 176: goto STRB_INST; \
3943 case 177: goto LDR_INST; \
3944 case 178: goto LDRCOND_INST ; \
3945 case 179: goto STR_INST; \
3946 case 180: goto CDP_INST; \
3947 case 181: goto STC_INST; \
3948 case 182: goto LDC_INST; \
3949 case 183: goto SWI_INST; \
3950 case 184: goto BBL_INST; \
3951 case 185: goto B_2_THUMB ; \
3952 case 186: goto B_COND_THUMB ; \
3953 case 187: goto BL_1_THUMB ; \
3954 case 188: goto BL_2_THUMB ; \
3955 case 189: goto BLX_1_THUMB ; \
3956 case 190: goto DISPATCH; \
3957 case 191: goto INIT_INST_LENGTH; \
3958 case 192: goto END; \
3959 }
3960#endif
3961
3962 #define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0)
3963 #define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1)
3964// #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((ISNEG(lop) && ISPOS(rop)) || \
3965 (ISNEG(lop) && ISPOS(dst)) || \
3966 (ISPOS(rop) && ISPOS(dst))))
3967 #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((dst < lop) || (dst < rop)))
3968 #define UPDATE_CFLAG_CARRY_FROM_ADD(lop, rop, flag) (cpu->CFlag = (((uint64_t) lop + (uint64_t) rop + (uint64_t) flag) > 0xffffffff) )
3969 #define UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(lop, rop, flag) (cpu->CFlag = ((uint64_t) lop >= ((uint64_t) rop + (uint64_t) flag)))
3970 #define UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop) (cpu->CFlag = (lop >= rop))
3971 #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) (cpu->CFlag = !(dst < lop))
3972 #define UPDATE_CFLAG_WITH_SC cpu->CFlag = cpu->shifter_carry_out
3973// #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || \
3974 (ISNEG(lop) && ISPOS(dst)) || \
3975 (ISPOS(rop) && ISPOS(dst)))
3976 #define UPDATE_VFLAG(dst, lop, rop) (cpu->VFlag = (((lop < 0) && (rop < 0) && (dst >= 0)) || \
3977 ((lop >= 0) && (rop) >= 0 && (dst < 0))))
3978 #define UPDATE_VFLAG_WITH_NOT(dst, lop, rop) (cpu->VFlag = !(((lop < 0) && (rop < 0) && (dst >= 0)) || \
3979 ((lop >= 0) && (rop) >= 0 && (dst < 0))))
3980 #define UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop) (cpu->VFlag = (((lop ^ rop) & (lop ^ dst)) >> 31))
3981
3982 #define SAVE_NZCVT cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | \
3983 (cpu->NFlag << 31) | \
3984 (cpu->ZFlag << 30) | \
3985 (cpu->CFlag << 29) | \
3986 (cpu->VFlag << 28) | \
3987 (cpu->TFlag << 5)
3988 #define LOAD_NZCVT cpu->NFlag = (cpu->Cpsr >> 31); \
3989 cpu->ZFlag = (cpu->Cpsr >> 30) & 1; \
3990 cpu->CFlag = (cpu->Cpsr >> 29) & 1; \
3991 cpu->VFlag = (cpu->Cpsr >> 28) & 1; \
3992 cpu->TFlag = (cpu->Cpsr >> 5) & 1;
3993
3994 #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE)
3995 #define PC (cpu->Reg[15])
3996 #define CHECK_EXT_INT if (!cpu->NirqSig) { \
3997 if (!(cpu->Cpsr & 0x80)) { \
3998 goto END; \
3999 } \
4000 }
4001
4002
4003
4004 //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
4005 arm_processor *cpu = state; //(arm_processor *)(core->cpu_data->obj);
4006
4007 // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback
4008 // to a clunky switch statement.
4009#if defined __GNUC__ || defined __clang__
4010 void *InstLabel[] = {
4011 #define VFP_INTERPRETER_LABEL
4012 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
4013 #undef VFP_INTERPRETER_LABEL
4014 &&SRS_INST,&&RFE_INST,&&BKPT_INST,&&BLX_INST,&&CPS_INST,&&PLD_INST,&&SETEND_INST,&&CLREX_INST,&&REV16_INST,&&USAD8_INST,&&SXTB_INST,
4015 &&UXTB_INST,&&SXTH_INST,&&SXTB16_INST,&&UXTH_INST,&&UXTB16_INST,&&CPY_INST,&&UXTAB_INST,&&SSUB8_INST,&&SHSUB8_INST,&&SSUBADDX_INST,
4016 &&STREX_INST,&&STREXB_INST,&&SWP_INST,&&SWPB_INST,&&SSUB16_INST,&&SSAT16_INST,&&SHSUBADDX_INST,&&QSUBADDX_INST,&&SHADDSUBX_INST,
4017 &&SHADD8_INST,&&SHADD16_INST,&&SEL_INST,&&SADDSUBX_INST,&&SADD8_INST,&&SADD16_INST,&&SHSUB16_INST,&&UMAAL_INST,&&UXTAB16_INST,
4018 &&USUBADDX_INST,&&USUB8_INST,&&USUB16_INST,&&USAT16_INST,&&USADA8_INST,&&UQSUBADDX_INST,&&UQSUB8_INST,&&UQSUB16_INST,
4019 &&UQADDSUBX_INST,&&UQADD8_INST,&&UQADD16_INST,&&SXTAB_INST,&&UHSUBADDX_INST,&&UHSUB8_INST,&&UHSUB16_INST,&&UHADDSUBX_INST,&&UHADD8_INST,
4020 &&UHADD16_INST,&&UADDSUBX_INST,&&UADD8_INST,&&UADD16_INST,&&SXTAH_INST,&&SXTAB16_INST,&&QADD8_INST,&&BXJ_INST,&&CLZ_INST,&&UXTAH_INST,
4021 &&BX_INST,&&REV_INST,&&BLX_INST,&&REVSH_INST,&&QADD_INST,&&QADD16_INST,&&QADDSUBX_INST,&&LDREX_INST,&&QDADD_INST,&&QDSUB_INST,
4022 &&QSUB_INST,&&LDREXB_INST,&&QSUB8_INST,&&QSUB16_INST,&&SMUAD_INST,&&SMMUL_INST,&&SMUSD_INST,&&SMLSD_INST,&&SMLSLD_INST,&&SMMLA_INST,
4023 &&SMMLS_INST,&&SMLALD_INST,&&SMLAD_INST,&&SMLAW_INST,&&SMULW_INST,&&PKHTB_INST,&&PKHBT_INST,&&SMUL_INST,&&SMLAL_INST,&&SMLA_INST,
4024 &&MCRR_INST,&&MRRC_INST,&&CMP_INST,&&TST_INST,&&TEQ_INST,&&CMN_INST,&&SMULL_INST,&&UMULL_INST,&&UMLAL_INST,&&SMLAL_INST,&&MUL_INST,
4025 &&MLA_INST,&&SSAT_INST,&&USAT_INST,&&MRS_INST,&&MSR_INST,&&AND_INST,&&BIC_INST,&&LDM_INST,&&EOR_INST,&&ADD_INST,&&RSB_INST,&&RSC_INST,
4026 &&SBC_INST,&&ADC_INST,&&SUB_INST,&&ORR_INST,&&MVN_INST,&&MOV_INST,&&STM_INST,&&LDM_INST,&&LDRSH_INST,&&STM_INST,&&LDM_INST,&&LDRSB_INST,
4027 &&STRD_INST,&&LDRH_INST,&&STRH_INST,&&LDRD_INST,&&STRT_INST,&&STRBT_INST,&&LDRBT_INST,&&LDRT_INST,&&MRC_INST,&&MCR_INST,&&MSR_INST,
4028 &&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,
4029 &&BL_1_THUMB, &&BL_2_THUMB, &&BLX_1_THUMB, &&DISPATCH,&&INIT_INST_LENGTH,&&END
4030 };
4031#endif
4032 arm_inst * inst_base;
4033 unsigned int lop, rop, dst;
4034 unsigned int addr;
4035 unsigned int phys_addr;
4036 unsigned int last_pc = 0;
4037 unsigned int num_instrs = 0;
4038 fault_t fault;
4039 static unsigned int last_physical_base = 0, last_logical_base = 0;
4040 int ptr;
4041 bool single_step = (cpu->NumInstrsToExecute == 1);
4042
4043 LOAD_NZCVT;
4044 DISPATCH:
4045 {
4046 if (!cpu->NirqSig) {
4047 if (!(cpu->Cpsr & 0x80)) {
4048 goto END;
4049 }
4050 }
4051
4052 if (cpu->TFlag) {
4053 cpu->Reg[15] &= 0xfffffffe;
4054 } else
4055 cpu->Reg[15] &= 0xfffffffc;
4056#if PROFILE
4057 /* check next instruction address is valid. */
4058 last_pc = cpu->Reg[15];
4059#endif
4060#if USER_MODE_OPT
4061 phys_addr = cpu->Reg[15];
4062#else
4063 {
4064 if (last_logical_base == (cpu->Reg[15] & 0xfffff000))
4065 phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff);
4066 else {
4067 /* check next instruction address is valid. */
4068 fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB);
4069 if (fault) {
4070 cpu->abortSig = true;
4071 cpu->Aborted = ARMul_PrefetchAbortV;
4072 cpu->AbortAddr = cpu->Reg[15];
4073 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
4074 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15];
4075 goto END;
4076 }
4077 last_logical_base = cpu->Reg[15] & 0xfffff000;
4078 last_physical_base = phys_addr & 0xfffff000;
4079 }
4080 }
4081#if HYBRID_MODE
4082 /* check if the native code of dyncom is available */
4083 //fast_map hash_map = core->dyncom_engine->fmap;
4084 //void * pfunc = NULL;
4085 //PFUNC(phys_addr);
4086 //if(pfunc){
4087 if(is_translated_entry(core, phys_addr)){
4088 int rc = JIT_RETURN_NOERR;
4089 //DEBUG_LOG(ARM11, "enter jit icounter is %lld, pc=0x%x\n", core->icounter, cpu->Reg[15]);
4090 SAVE_NZCVT;
4091// resume_timing();
4092 rc = cpu_run(core);
4093 LOAD_NZCVT;
4094 //DEBUG_LOG(ARM11, "out of jit ret is %d icounter is %lld, pc=0x%x\n", rc, core->icounter, cpu->Reg[15]);
4095 if((rc == JIT_RETURN_FUNCNOTFOUND) || (rc == JIT_RETURN_FUNC_BLANK)){
4096 /* keep the tflag same with the bit in CPSR */
4097 //cpu->TFlag = cpu->Cpsr & (1 << THUMB_BIT);
4098 //cpu->TFlag = cpu->Cpsr & (1 << 5);
4099 //switch_mode(cpu, cpu->Cpsr & 0x1f);
4100 //DEBUG_LOG(ARM11, "FUNCTION not found , pc=0x%x\n", cpu->Reg[15]);
4101 fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB);
4102 if (fault) {
4103 cpu->abortSig = true;
4104 cpu->Aborted = ARMul_PrefetchAbortV;
4105 cpu->AbortAddr = cpu->Reg[15];
4106 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
4107 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15];
4108 goto END;
4109 }
4110 last_logical_base = cpu->Reg[15] & 0xfffff000;
4111 last_physical_base = phys_addr & 0xfffff000;
4112 core->current_page_phys = last_physical_base;
4113 core->current_page_effec = last_logical_base;
4114 //push_to_compiled(core, phys_addr);
4115 }
4116 else{
4117 if((cpu->CP15[CP15(CP15_TLB_FAULT_STATUS)] & 0xf0)){
4118 //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]);
4119 //core->Reg[15] -= get_instr_size(cpu_dyncom);
4120 fill_tlb(cpu);
4121 goto END;
4122 }
4123 if (cpu->syscallSig) {
4124 goto END;
4125 }
4126 if (cpu->abortSig) {
4127 cpu->CP15[CP15_TLB_FAULT_STATUS - CP15_BASE] &= 0xFFFFFFF0;
4128 goto END;
4129 }
4130 if (!cpu->NirqSig) {
4131 if (!(cpu->Cpsr & 0x80)) {
4132 goto END;
4133 }
4134 }
4135
4136 /* if regular trap */
4137 cpu->Reg[15] += GET_INST_SIZE(cpu);
4138 /*uint32_t mode = cpu->Cpsr & 0x1f;
4139 if ((mode != cpu->Mode) && (!is_user_mode(core))) {
4140 switch_mode(cpu, mode);
4141 return 1;
4142 }*/
4143
4144 goto END;
4145 }
4146 //phys_addr = cpu->Reg[15];
4147 }
4148 else{
4149 if (last_logical_base == (cpu->Reg[15] & 0xfffff000))
4150 phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff);
4151 else {
4152 /* check next instruction address is valid. */
4153 fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB);
4154 if (fault) {
4155 cpu->abortSig = true;
4156 cpu->Aborted = ARMul_PrefetchAbortV;
4157 cpu->AbortAddr = cpu->Reg[15];
4158 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
4159 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15];
4160 goto END;
4161 }
4162 last_logical_base = cpu->Reg[15] & 0xfffff000;
4163 last_physical_base = phys_addr & 0xfffff000;
4164 }
4165 }
4166#endif /* #if HYBRID_MODE */
4167#endif /* #if USER_MODE_OPT */
4168 if (true){//if(is_fast_interp_code(core, phys_addr)){
4169 if (find_bb(phys_addr, ptr) == -1)
4170 if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
4171 goto END;
4172 }
4173 else{
4174 if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
4175 goto END;
4176 }
4177#if PROFILE
4178 resume_timing();
4179#endif
4180 inst_base = (arm_inst *)&inst_buf[ptr];
4181 GOTO_NEXT_INST;
4182 }
4183 ADC_INST:
4184 {
4185 INC_ICOUNTER;
4186 adc_inst *inst_cream = (adc_inst *)inst_base->component;
4187 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4188 lop = RN;
4189 unsigned int sht_op = SHIFTER_OPERAND;
4190 rop = SHIFTER_OPERAND + cpu->CFlag;
4191 RD = dst = lop + rop;
4192 if (inst_cream->S && (inst_cream->Rd == 15)) {
4193 /* cpsr = spsr */
4194 if (CurrentModeHasSPSR) {
4195 cpu->Cpsr = cpu->Spsr_copy;
4196 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
4197 LOAD_NZCVT;
4198 }
4199 } else if (inst_cream->S) {
4200 UPDATE_NFLAG(dst);
4201 UPDATE_ZFLAG(dst);
4202 UPDATE_CFLAG_CARRY_FROM_ADD(lop, sht_op, cpu->CFlag);
4203 UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4204 }
4205 if (inst_cream->Rd == 15) {
4206 INC_PC(sizeof(adc_inst));
4207 goto DISPATCH;
4208 }
4209 }
4210 cpu->Reg[15] += GET_INST_SIZE(cpu);
4211 INC_PC(sizeof(adc_inst));
4212 FETCH_INST;
4213 GOTO_NEXT_INST;
4214 }
4215 ADD_INST:
4216 {
4217 INC_ICOUNTER;
4218 add_inst *inst_cream = (add_inst *)inst_base->component;
4219 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4220 lop = RN;
4221 if (inst_cream->Rn == 15) {
4222 lop += 2 * GET_INST_SIZE(cpu);
4223 }
4224 rop = SHIFTER_OPERAND;
4225 RD = dst = lop + rop;
4226 if (inst_cream->S && (inst_cream->Rd == 15)) {
4227 /* cpsr = spsr*/
4228 if (CurrentModeHasSPSR) {
4229 cpu->Cpsr = cpu->Spsr_copy;
4230 switch_mode(cpu, cpu->Cpsr & 0x1f);
4231 LOAD_NZCVT;
4232 }
4233 } else if (inst_cream->S) {
4234 UPDATE_NFLAG(dst);
4235 UPDATE_ZFLAG(dst);
4236 UPDATE_CFLAG(dst, lop, rop);
4237 UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4238 }
4239 if (inst_cream->Rd == 15) {
4240 INC_PC(sizeof(add_inst));
4241 goto DISPATCH;
4242 }
4243 }
4244 cpu->Reg[15] += GET_INST_SIZE(cpu);
4245 INC_PC(sizeof(add_inst));
4246 FETCH_INST;
4247 GOTO_NEXT_INST;
4248 }
4249 AND_INST:
4250 {
4251 INC_ICOUNTER;
4252 and_inst *inst_cream = (and_inst *)inst_base->component;
4253 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4254 lop = RN;
4255 rop = SHIFTER_OPERAND;
4256 RD = dst = lop & rop;
4257 if (inst_cream->S && (inst_cream->Rd == 15)) {
4258 /* cpsr = spsr*/
4259 if (CurrentModeHasSPSR) {
4260 cpu->Cpsr = cpu->Spsr_copy;
4261 switch_mode(cpu, cpu->Cpsr & 0x1f);
4262 LOAD_NZCVT;
4263 }
4264 } else if (inst_cream->S) {
4265 UPDATE_NFLAG(dst);
4266 UPDATE_ZFLAG(dst);
4267 UPDATE_CFLAG_WITH_SC;
4268 //UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4269 }
4270 if (inst_cream->Rd == 15) {
4271 INC_PC(sizeof(and_inst));
4272 goto DISPATCH;
4273 }
4274 }
4275 cpu->Reg[15] += GET_INST_SIZE(cpu);
4276 INC_PC(sizeof(and_inst));
4277 FETCH_INST;
4278 GOTO_NEXT_INST;
4279 }
4280 BBL_INST:
4281 {
4282 INC_ICOUNTER;
4283 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4284 bbl_inst *inst_cream = (bbl_inst *)inst_base->component;
4285 if (inst_cream->L) {
4286 LINK_RTN_ADDR;
4287 }
4288 SET_PC;
4289 INC_PC(sizeof(bbl_inst));
4290 goto DISPATCH;
4291 }
4292 cpu->Reg[15] += GET_INST_SIZE(cpu);
4293 INC_PC(sizeof(bbl_inst));
4294 goto DISPATCH;
4295 }
4296 BIC_INST:
4297 {
4298 INC_ICOUNTER;
4299 bic_inst *inst_cream = (bic_inst *)inst_base->component;
4300 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4301 lop = RN;
4302 if (inst_cream->Rn == 15) {
4303 lop += 2 * GET_INST_SIZE(cpu);
4304 }
4305 rop = SHIFTER_OPERAND;
4306// RD = dst = lop & (rop ^ 0xffffffff);
4307 RD = dst = lop & (~rop);
4308 if ((inst_cream->S) && (inst_cream->Rd == 15)) {
4309 /* cpsr = spsr */
4310 if (CurrentModeHasSPSR) {
4311 cpu->Cpsr = cpu->Spsr_copy;
4312 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
4313 LOAD_NZCVT;
4314 }
4315 } else if (inst_cream->S) {
4316 UPDATE_NFLAG(dst);
4317 UPDATE_ZFLAG(dst);
4318 UPDATE_CFLAG_WITH_SC;
4319 }
4320 if (inst_cream->Rd == 15) {
4321 INC_PC(sizeof(bic_inst));
4322 goto DISPATCH;
4323 }
4324 }
4325 cpu->Reg[15] += GET_INST_SIZE(cpu);
4326 INC_PC(sizeof(bic_inst));
4327 FETCH_INST;
4328 GOTO_NEXT_INST;
4329 }
4330 BKPT_INST:
4331 BLX_INST:
4332 {
4333 INC_ICOUNTER;
4334 blx_inst *inst_cream = (blx_inst *)inst_base->component;
4335 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4336 unsigned int inst = inst_cream->inst;
4337 if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
4338 //LINK_RTN_ADDR;
4339 cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu));
4340 if(cpu->TFlag)
4341 cpu->Reg[14] |= 0x1;
4342 cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe;
4343 cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1;
4344 //cpu->Reg[15] = cpu->Reg[BITS(inst, 0, 3)] & 0xfffffffe;
4345 //cpu->TFlag = cpu->Reg[BITS(inst, 0, 3)] & 0x1;
4346 } else {
4347 cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu));
4348 cpu->TFlag = 0x1;
4349 int signed_int = inst_cream->val.signed_immed_24;
4350 signed_int = (signed_int) & 0x800000 ? (0x3F000000 | signed_int) : signed_int;
4351 signed_int = signed_int << 2;
4352 // cpu->Reg[15] = cpu->Reg[15] + 2 * GET_INST_SIZE(cpu)
4353 cpu->Reg[15] = cpu->Reg[15] + 8
4354 + signed_int + (BIT(inst, 24) << 1);
4355 //DEBUG_MSG;
4356 }
4357 INC_PC(sizeof(blx_inst));
4358 goto DISPATCH;
4359 }
4360 cpu->Reg[15] += GET_INST_SIZE(cpu);
4361// INC_PC(sizeof(bx_inst));
4362 INC_PC(sizeof(blx_inst));
4363 goto DISPATCH;
4364 }
4365 BX_INST:
4366 {
4367 INC_ICOUNTER;
4368 bx_inst *inst_cream = (bx_inst *)inst_base->component;
4369 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4370 if (inst_cream->Rm == 15)
4371 DEBUG_LOG(ARM11, "In %s, BX at pc %x: use of Rm = R15 is discouraged\n", __FUNCTION__, cpu->Reg[15]);
4372 cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1;
4373 cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe;
4374// cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1;
4375 INC_PC(sizeof(bx_inst));
4376 goto DISPATCH;
4377 }
4378 cpu->Reg[15] += GET_INST_SIZE(cpu);
4379// INC_PC(sizeof(bx_inst));
4380 INC_PC(sizeof(bx_inst));
4381 goto DISPATCH;
4382 }
4383 BXJ_INST:
4384 CDP_INST:
4385 {
4386 INC_ICOUNTER;
4387 cdp_inst *inst_cream = (cdp_inst *)inst_base->component;
4388 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4389 /* FIXME, check if cp access allowed */
4390 #define CP_ACCESS_ALLOW 0
4391 if(CP_ACCESS_ALLOW){
4392 /* undefined instruction here */
4393 cpu->NumInstrsToExecute = 0;
4394 return num_instrs;
4395 }
4396 ERROR_LOG(ARM11, "CDP insn inst=0x%x, pc=0x%x\n", inst_cream->inst, cpu->Reg[15]);
4397 unsigned cpab = (cpu->CDP[inst_cream->cp_num]) (cpu, ARMul_FIRST, inst_cream->inst);
4398 if(cpab != ARMul_DONE){
4399 ERROR_LOG(ARM11, "CDP insn wrong, inst=0x%x, cp_num=0x%x\n", inst_cream->inst, inst_cream->cp_num);
4400 //CITRA_IGNORE_EXIT(-1);
4401 }
4402 }
4403 cpu->Reg[15] += GET_INST_SIZE(cpu);
4404 INC_PC(sizeof(cdp_inst));
4405 FETCH_INST;
4406 GOTO_NEXT_INST;
4407 }
4408
4409 CLREX_INST:
4410 {
4411 INC_ICOUNTER;
4412 remove_exclusive(cpu, 0);
4413 cpu->exclusive_state = 0;
4414
4415 cpu->Reg[15] += GET_INST_SIZE(cpu);
4416 INC_PC(sizeof(clrex_inst));
4417 FETCH_INST;
4418 GOTO_NEXT_INST;
4419 }
4420 CLZ_INST:
4421 {
4422 INC_ICOUNTER;
4423 clz_inst *inst_cream = (clz_inst *)inst_base->component;
4424 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4425 RD = clz(RM);
4426 }
4427 cpu->Reg[15] += GET_INST_SIZE(cpu);
4428 INC_PC(sizeof(clz_inst));
4429 FETCH_INST;
4430 GOTO_NEXT_INST;
4431 }
4432 CMN_INST:
4433 {
4434 INC_ICOUNTER;
4435 cmn_inst *inst_cream = (cmn_inst *)inst_base->component;
4436 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4437// DEBUG_LOG(ARM11, "RN is %x\n", RN);
4438 lop = RN;
4439 rop = SHIFTER_OPERAND;
4440 dst = lop + rop;
4441 UPDATE_NFLAG(dst);
4442 UPDATE_ZFLAG(dst);
4443 UPDATE_CFLAG(dst, lop, rop);
4444 UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4445 }
4446 cpu->Reg[15] += GET_INST_SIZE(cpu);
4447 INC_PC(sizeof(cmn_inst));
4448 FETCH_INST;
4449 GOTO_NEXT_INST;
4450 }
4451 CMP_INST:
4452 {
4453// DEBUG_LOG(ARM11, "cmp inst\n");
4454// DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]);
4455 INC_ICOUNTER;
4456 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4457// DEBUG_LOG(ARM11, "r0 is %x\n", cpu->Reg[0]);
4458 cmp_inst *inst_cream = (cmp_inst *)inst_base->component;
4459 lop = RN;
4460 if (inst_cream->Rn == 15) {
4461 lop += 2 * GET_INST_SIZE(cpu);
4462 }
4463 rop = SHIFTER_OPERAND;
4464 dst = lop - rop;
4465
4466 UPDATE_NFLAG(dst);
4467 UPDATE_ZFLAG(dst);
4468// UPDATE_CFLAG(dst, lop, rop);
4469 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
4470// UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4471 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
4472// UPDATE_VFLAG_WITH_NOT(dst, lop, rop);
4473 }
4474 cpu->Reg[15] += GET_INST_SIZE(cpu);
4475 INC_PC(sizeof(cmp_inst));
4476 FETCH_INST;
4477 GOTO_NEXT_INST;
4478 }
4479 CPS_INST:
4480 {
4481 INC_ICOUNTER;
4482 cps_inst *inst_cream = (cps_inst *)inst_base->component;
4483 uint32_t aif_val = 0;
4484 uint32_t aif_mask = 0;
4485 if (InAPrivilegedMode(cpu)) {
4486 /* isInAPrivilegedMode */
4487 if (inst_cream->imod1) {
4488 if (inst_cream->A) {
4489 aif_val |= (inst_cream->imod0 << 8);
4490 aif_mask |= 1 << 8;
4491 }
4492 if (inst_cream->I) {
4493 aif_val |= (inst_cream->imod0 << 7);
4494 aif_mask |= 1 << 7;
4495 }
4496 if (inst_cream->F) {
4497 aif_val |= (inst_cream->imod0 << 6);
4498 aif_mask |= 1 << 6;
4499 }
4500 aif_mask = ~aif_mask;
4501 cpu->Cpsr = (cpu->Cpsr & aif_mask) | aif_val;
4502 }
4503 if (inst_cream->mmod) {
4504 cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode;
4505 switch_mode(cpu, inst_cream->mode);
4506 }
4507 }
4508 cpu->Reg[15] += GET_INST_SIZE(cpu);
4509 INC_PC(sizeof(cps_inst));
4510 FETCH_INST;
4511 GOTO_NEXT_INST;
4512 }
4513 CPY_INST:
4514 {
4515 INC_ICOUNTER;
4516 mov_inst *inst_cream = (mov_inst *)inst_base->component;
4517// cpy_inst *inst_cream = (cpy_inst *)inst_base->component;
4518 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4519 RD = SHIFTER_OPERAND;
4520// RD = RM;
4521 if ((inst_cream->Rd == 15)) {
4522 INC_PC(sizeof(mov_inst));
4523 goto DISPATCH;
4524 }
4525 }
4526// DEBUG_LOG(ARM11, "cpy inst %x\n", cpu->Reg[15]);
4527 cpu->Reg[15] += GET_INST_SIZE(cpu);
4528 INC_PC(sizeof(mov_inst));
4529 FETCH_INST;
4530 GOTO_NEXT_INST;
4531 }
4532 EOR_INST:
4533 {
4534 INC_ICOUNTER;
4535 eor_inst *inst_cream = (eor_inst *)inst_base->component;
4536 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4537 lop = RN;
4538 if (inst_cream->Rn == 15) {
4539 lop += 2 * GET_INST_SIZE(cpu);
4540 }
4541 rop = SHIFTER_OPERAND;
4542 RD = dst = lop ^ rop;
4543 if (inst_cream->S && (inst_cream->Rd == 15)) {
4544 /* cpsr = spsr*/
4545 if (CurrentModeHasSPSR) {
4546 cpu->Cpsr = cpu->Spsr_copy;
4547 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
4548 LOAD_NZCVT;
4549 }
4550 } else if (inst_cream->S) {
4551 UPDATE_NFLAG(dst);
4552 UPDATE_ZFLAG(dst);
4553 UPDATE_CFLAG_WITH_SC;
4554// UPDATE_CFLAG(dst, lop, rop);
4555// UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4556 }
4557 if (inst_cream->Rd == 15) {
4558 INC_PC(sizeof(eor_inst));
4559 goto DISPATCH;
4560 }
4561 }
4562 cpu->Reg[15] += GET_INST_SIZE(cpu);
4563 INC_PC(sizeof(eor_inst));
4564 FETCH_INST;
4565 GOTO_NEXT_INST;
4566 }
4567 LDC_INST:
4568 {
4569 INC_ICOUNTER;
4570 /* NOT IMPL */
4571 cpu->Reg[15] += GET_INST_SIZE(cpu);
4572 INC_PC(sizeof(ldc_inst));
4573 FETCH_INST;
4574 GOTO_NEXT_INST;
4575 }
4576 LDM_INST:
4577 {
4578 INC_ICOUNTER;
4579 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4580 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4581 int i;
4582 unsigned int ret;
4583 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4584 if (fault) {
4585 goto MMU_EXCEPTION;
4586 }
4587 unsigned int inst = inst_cream->inst;
4588 if (BIT(inst, 22) && !BIT(inst, 15)) {
4589// DEBUG_MSG;
4590 #if 1
4591 /* LDM (2) user */
4592 for (i = 0; i < 13; i++) {
4593 if(BIT(inst, i)){
4594 #if 0
4595 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4596 if (fault) {
4597 goto MMU_EXCEPTION;
4598 }
4599 #endif
4600 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4601 //if (fault) goto MMU_EXCEPTION;
4602 cpu->Reg[i] = ret;
4603 addr += 4;
4604 if ((addr & 0xfff) == 0) {
4605 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4606 } else {
4607 phys_addr += 4;
4608 }
4609 }
4610 }
4611 if (BIT(inst, 13)) {
4612 #if 0
4613 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4614 if (fault) {
4615 goto MMU_EXCEPTION;
4616 }
4617 #endif
4618 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4619 //if (fault) goto MMU_EXCEPTION;
4620 if (cpu->Mode == USER32MODE)
4621 cpu->Reg[13] = ret;
4622 else
4623 cpu->Reg_usr[0] = ret;
4624 addr += 4;
4625 if ((addr & 0xfff) == 0) {
4626 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4627 } else {
4628 phys_addr += 4;
4629 }
4630 }
4631 if (BIT(inst, 14)) {
4632 #if 0
4633 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4634 if (fault) {
4635 goto MMU_EXCEPTION;
4636 }
4637 #endif
4638 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4639 //if (fault) goto MMU_EXCEPTION;
4640 if (cpu->Mode == USER32MODE)
4641 cpu->Reg[14] = ret;
4642 else
4643 cpu->Reg_usr[1] = ret;
4644 }
4645 #endif
4646 } else if (!BIT(inst, 22)) {
4647 for( i = 0; i < 16; i ++ ){
4648 if(BIT(inst, i)){
4649 //bus_read(32, addr, &ret);
4650 #if 0
4651 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4652 if (fault) {
4653 goto MMU_EXCEPTION;
4654 }
4655 #endif
4656 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4657 if (fault) goto MMU_EXCEPTION;
4658 /* For armv5t, should enter thumb when bits[0] is non-zero. */
4659 if(i == 15){
4660 cpu->TFlag = ret & 0x1;
4661 ret &= 0xFFFFFFFE;
4662 //DEBUG_LOG(ARM11, "In %s, TFlag ret=0x%x\n", __FUNCTION__, ret);
4663 }
4664
4665 cpu->Reg[i] = ret;
4666 addr += 4;
4667 if ((addr & 0xfff) == 0) {
4668 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4669 } else {
4670 phys_addr += 4;
4671 }
4672 }
4673 }
4674 } else if (BIT(inst, 22) && BIT(inst, 15)) {
4675 for( i = 0; i < 15; i ++ ){
4676 if(BIT(inst, i)){
4677 #if 0
4678 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4679 if (fault) {
4680 goto MMU_EXCEPTION;
4681 }
4682 #endif
4683 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4684 //if (fault) goto MMU_EXCEPTION;
4685 cpu->Reg[i] = ret;
4686 addr += 4;
4687 if ((addr & 0xfff) == 0) {
4688 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4689 } else {
4690 phys_addr += 4;
4691 }
4692 }
4693 }
4694
4695 if (CurrentModeHasSPSR) {
4696 cpu->Cpsr = cpu->Spsr_copy;
4697 switch_mode(cpu, cpu->Cpsr & 0x1f);
4698 LOAD_NZCVT;
4699 }
4700 #if 0
4701 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4702 if (fault) {
4703 goto MMU_EXCEPTION;
4704 }
4705 #endif
4706 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4707 if (fault) {
4708 goto MMU_EXCEPTION;
4709 }
4710 cpu->Reg[15] = ret;
4711 #if 0
4712 addr += 4;
4713 phys_addr += 4;
4714 #endif
4715 }
4716 if (BIT(inst, 15)) {
4717 INC_PC(sizeof(ldst_inst));
4718 goto DISPATCH;
4719 }
4720 }
4721 cpu->Reg[15] += GET_INST_SIZE(cpu);
4722 INC_PC(sizeof(ldst_inst));
4723 FETCH_INST;
4724 GOTO_NEXT_INST;
4725 }
4726 SXTH_INST:
4727 {
4728 INC_ICOUNTER;
4729 sxth_inst *inst_cream = (sxth_inst *)inst_base->component;
4730 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4731 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
4732 if (BIT(operand2, 15)) {
4733 operand2 |= 0xffff0000;
4734 } else {
4735 operand2 &= 0xffff;
4736 }
4737 RD = operand2;
4738 }
4739 cpu->Reg[15] += GET_INST_SIZE(cpu);
4740 INC_PC(sizeof(sxth_inst));
4741 FETCH_INST;
4742 GOTO_NEXT_INST;
4743 }
4744 LDR_INST:
4745 {
4746 INC_ICOUNTER;
4747 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4748 //if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4749 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4750 if (fault) goto MMU_EXCEPTION;
4751 unsigned int value;
4752 //bus_read(32, addr, &value);
4753 fault = interpreter_read_memory(addr, phys_addr, value, 32);
4754 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
4755 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4756 else {
4757 value = ROTATE_RIGHT_32(value,(8*(addr&0x3)));
4758 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4759 }
4760 if (BITS(inst_cream->inst, 12, 15) == 15) {
4761 /* For armv5t, should enter thumb when bits[0] is non-zero. */
4762 cpu->TFlag = value & 0x1;
4763 cpu->Reg[15] &= 0xFFFFFFFE;
4764 INC_PC(sizeof(ldst_inst));
4765 goto DISPATCH;
4766 }
4767 //}
4768 cpu->Reg[15] += GET_INST_SIZE(cpu);
4769 INC_PC(sizeof(ldst_inst));
4770 FETCH_INST;
4771 GOTO_NEXT_INST;
4772 }
4773 LDRCOND_INST:
4774 {
4775 INC_ICOUNTER;
4776 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4777 if (CondPassed(cpu, inst_base->cond)) {
4778 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4779 if (fault) goto MMU_EXCEPTION;
4780 unsigned int value;
4781 //bus_read(32, addr, &value);
4782 fault = interpreter_read_memory(addr, phys_addr, value, 32);
4783 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
4784 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4785 else {
4786 value = ROTATE_RIGHT_32(value,(8*(addr&0x3)));
4787 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4788 }
4789
4790 if (BITS(inst_cream->inst, 12, 15) == 15) {
4791 /* For armv5t, should enter thumb when bits[0] is non-zero. */
4792 cpu->TFlag = value & 0x1;
4793 cpu->Reg[15] &= 0xFFFFFFFE;
4794 INC_PC(sizeof(ldst_inst));
4795 goto DISPATCH;
4796 }
4797 }
4798 cpu->Reg[15] += GET_INST_SIZE(cpu);
4799 INC_PC(sizeof(ldst_inst));
4800 FETCH_INST;
4801 GOTO_NEXT_INST;
4802 }
4803 UXTH_INST:
4804 {
4805 INC_ICOUNTER;
4806 uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
4807 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4808 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
4809 & 0xffff;
4810 RD = operand2;
4811 }
4812 cpu->Reg[15] += GET_INST_SIZE(cpu);
4813 INC_PC(sizeof(uxth_inst));
4814 FETCH_INST;
4815 GOTO_NEXT_INST;
4816 }
4817 UXTAH_INST:
4818 {
4819 INC_ICOUNTER;
4820 uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component;
4821 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4822 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
4823 & 0xffff;
4824 RD = RN + operand2;
4825 if (inst_cream->Rn == 15 || inst_cream->Rm == 15) {
4826 DEBUG_LOG(ARM11, "in line %d\n", __LINE__);
4827 CITRA_IGNORE_EXIT(-1);
4828 }
4829 }
4830 cpu->Reg[15] += GET_INST_SIZE(cpu);
4831 INC_PC(sizeof(uxtah_inst));
4832 FETCH_INST;
4833 GOTO_NEXT_INST;
4834 }
4835 LDRB_INST:
4836 {
4837 INC_ICOUNTER;
4838 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4839 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4840 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4841 if (fault) goto MMU_EXCEPTION;
4842 unsigned int value;
4843 fault = interpreter_read_memory(addr, phys_addr, value, 8);
4844 if (fault) goto MMU_EXCEPTION;
4845 //bus_read(8, addr, &value);
4846 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4847 if (BITS(inst_cream->inst, 12, 15) == 15) {
4848 INC_PC(sizeof(ldst_inst));
4849 goto DISPATCH;
4850 }
4851 }
4852 cpu->Reg[15] += GET_INST_SIZE(cpu);
4853 INC_PC(sizeof(ldst_inst));
4854 FETCH_INST;
4855 GOTO_NEXT_INST;
4856 }
4857 LDRBT_INST:
4858 {
4859 INC_ICOUNTER;
4860 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4861 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4862 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4863 if (fault) goto MMU_EXCEPTION;
4864 unsigned int value;
4865 fault = interpreter_read_memory(addr, phys_addr, value, 8);
4866 if (fault) goto MMU_EXCEPTION;
4867 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4868 if (BITS(inst_cream->inst, 12, 15) == 15) {
4869 INC_PC(sizeof(ldst_inst));
4870 goto DISPATCH;
4871 }
4872 }
4873 cpu->Reg[15] += GET_INST_SIZE(cpu);
4874 INC_PC(sizeof(ldst_inst));
4875 FETCH_INST;
4876 GOTO_NEXT_INST;
4877 }
4878 LDRD_INST:
4879 {
4880 INC_ICOUNTER;
4881 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4882 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4883 /* Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 || addr[2] == 0) */
4884 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4885 if (fault) goto MMU_EXCEPTION;
4886 uint32_t rear_phys_addr;
4887 fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 1);
4888 if(fault){
4889 ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n");
4890 CITRA_IGNORE_EXIT(-1);
4891 goto MMU_EXCEPTION;
4892 }
4893 unsigned int value;
4894 fault = interpreter_read_memory(addr, phys_addr, value, 32);
4895 if (fault) goto MMU_EXCEPTION;
4896 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4897 fault = interpreter_read_memory(addr + 4, rear_phys_addr, value, 32);
4898 if (fault) goto MMU_EXCEPTION;
4899 cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = value;
4900 /* No dispatch since this operation should not modify R15 */
4901 }
4902 cpu->Reg[15] += 4;
4903 INC_PC(sizeof(ldst_inst));
4904 FETCH_INST;
4905 GOTO_NEXT_INST;
4906 }
4907
4908 LDREX_INST:
4909 {
4910 INC_ICOUNTER;
4911 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4912 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4913 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
4914 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4915 if (fault) goto MMU_EXCEPTION;
4916 unsigned int value;
4917 fault = interpreter_read_memory(addr, phys_addr, value, 32);
4918 if (fault) goto MMU_EXCEPTION;
4919
4920 add_exclusive_addr(cpu, phys_addr);
4921 cpu->exclusive_state = 1;
4922
4923 //bus_read(32, addr, &value);
4924 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4925 if (BITS(inst_cream->inst, 12, 15) == 15) {
4926 INC_PC(sizeof(ldst_inst));
4927 goto DISPATCH;
4928 }
4929 }
4930 cpu->Reg[15] += GET_INST_SIZE(cpu);
4931 INC_PC(sizeof(ldst_inst));
4932 FETCH_INST;
4933 GOTO_NEXT_INST;
4934 }
4935 LDREXB_INST:
4936 {
4937 INC_ICOUNTER;
4938 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4939 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4940 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
4941 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4942 if (fault) goto MMU_EXCEPTION;
4943 unsigned int value;
4944 fault = interpreter_read_memory(addr, phys_addr, value, 8);
4945 if (fault) goto MMU_EXCEPTION;
4946
4947 add_exclusive_addr(cpu, phys_addr);
4948 cpu->exclusive_state = 1;
4949
4950 //bus_read(8, addr, &value);
4951 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4952 if (BITS(inst_cream->inst, 12, 15) == 15) {
4953 INC_PC(sizeof(ldst_inst));
4954 goto DISPATCH;
4955 }
4956 }
4957 cpu->Reg[15] += GET_INST_SIZE(cpu);
4958 INC_PC(sizeof(ldst_inst));
4959 FETCH_INST;
4960 GOTO_NEXT_INST;
4961 }
4962 LDRH_INST:
4963 {
4964 INC_ICOUNTER;
4965 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4966 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4967 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4968 if (fault) goto MMU_EXCEPTION;
4969 unsigned int value = 0;
4970 fault = interpreter_read_memory(addr, phys_addr, value, 16);
4971// fault = interpreter_read_memory(addr, value, 32);
4972 if (fault) goto MMU_EXCEPTION;
4973 //if (value == 0xffff && cpu->icounter > 190000000 && cpu->icounter < 210000000) {
4974 // value = 0xffffffff;
4975 //}
4976 //bus_read(16, addr, &value);
4977// cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value & 0xffff;
4978 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4979 if (BITS(inst_cream->inst, 12, 15) == 15) {
4980 INC_PC(sizeof(ldst_inst));
4981 goto DISPATCH;
4982 }
4983 }
4984 cpu->Reg[15] += GET_INST_SIZE(cpu);
4985 INC_PC(sizeof(ldst_inst));
4986 FETCH_INST;
4987 GOTO_NEXT_INST;
4988 }
4989 LDRSB_INST:
4990 {
4991 INC_ICOUNTER;
4992 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4993 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4994 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4995 if (fault) goto MMU_EXCEPTION;
4996 unsigned int value;
4997// DEBUG_LOG(ARM11, "ldrsb addr is %x\n", addr);
4998 fault = interpreter_read_memory(addr, phys_addr, value, 8);
4999 if (fault) goto MMU_EXCEPTION;
5000 //bus_read(8, addr, &value);
5001 if (BIT(value, 7)) {
5002 value |= 0xffffff00;
5003 }
5004 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5005 if (BITS(inst_cream->inst, 12, 15) == 15) {
5006 INC_PC(sizeof(ldst_inst));
5007 goto DISPATCH;
5008 }
5009 }
5010 cpu->Reg[15] += GET_INST_SIZE(cpu);
5011 INC_PC(sizeof(ldst_inst));
5012 FETCH_INST;
5013 GOTO_NEXT_INST;
5014 }
5015 LDRSH_INST:
5016 {
5017 INC_ICOUNTER;
5018 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5019 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5020 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
5021 if (fault) goto MMU_EXCEPTION;
5022 unsigned int value;
5023 fault = interpreter_read_memory(addr, phys_addr, value, 16);
5024 if (fault) goto MMU_EXCEPTION;
5025 //bus_read(16, addr, &value);
5026 if (BIT(value, 15)) {
5027 value |= 0xffff0000;
5028 }
5029 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5030 if (BITS(inst_cream->inst, 12, 15) == 15) {
5031 INC_PC(sizeof(ldst_inst));
5032 goto DISPATCH;
5033 }
5034 }
5035 cpu->Reg[15] += GET_INST_SIZE(cpu);
5036 INC_PC(sizeof(ldst_inst));
5037 FETCH_INST;
5038 GOTO_NEXT_INST;
5039 }
5040 LDRT_INST:
5041 {
5042 INC_ICOUNTER;
5043 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5044 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5045 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
5046 if (fault) goto MMU_EXCEPTION;
5047 unsigned int value;
5048 fault = interpreter_read_memory(addr, phys_addr, value, 32);
5049 if (fault) goto MMU_EXCEPTION;
5050 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5051
5052 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
5053 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5054 else
5055 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ROTATE_RIGHT_32(value,(8*(addr&0x3))) ;
5056
5057 if (BITS(inst_cream->inst, 12, 15) == 15) {
5058 INC_PC(sizeof(ldst_inst));
5059 goto DISPATCH;
5060 }
5061 }
5062 cpu->Reg[15] += GET_INST_SIZE(cpu);
5063 INC_PC(sizeof(ldst_inst));
5064 FETCH_INST;
5065 GOTO_NEXT_INST;
5066 }
5067 MCR_INST:
5068 {
5069 INC_ICOUNTER;
5070 /* NOT IMPL */
5071 mcr_inst *inst_cream = (mcr_inst *)inst_base->component;
5072 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5073 unsigned int inst = inst_cream->inst;
5074 if (inst_cream->Rd == 15) {
5075 DEBUG_MSG;
5076 } else {
5077 if (inst_cream->cp_num == 15) {
5078 if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) {
5079 //LET(RD, CONST(0x0007b000));
5080 //LET(RD, CONST(0x410FB760));
5081 //LET(CP15_MAIN_ID, R(RD));
5082 CP15_REG(CP15_MAIN_ID) = RD;
5083 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
5084 //LET(RD, R(CP15_CONTROL));
5085 CP15_REG(CP15_AUXILIARY_CONTROL) = RD;
5086 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
5087 //LET(RD, R(CP15_CONTROL));
5088 CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD;
5089 } else if(CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
5090 //LET(CP15_CONTROL, R(RD));
5091 CP15_REG(CP15_CONTROL) = RD;
5092 } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
5093 //LET(CP15_DOMAIN_ACCESS_CONTROL, R(RD));
5094 CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD;
5095 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
5096 //LET(CP15_TRANSLATION_BASE_TABLE_0, R(RD));
5097 CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD;
5098 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) {
5099 //LET(CP15_TRANSLATION_BASE_TABLE_1, R(RD));
5100 CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD;
5101 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) {
5102 //LET(CP15_TRANSLATION_BASE_CONTROL, R(RD));
5103 CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD;
5104 } else if(CRn == MMU_CACHE_OPS){
5105 //SKYEYE_WARNING("cache operation have not implemented.\n");
5106 } else if(CRn == MMU_TLB_OPS){
5107 switch (CRm) {
5108 case 5: /* ITLB */
5109 switch(OPCODE_2){
5110 case 0: /* invalidate all */
5111 //invalidate_all_tlb(state);
5112 DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate all\n");
5113 //remove_tlb(INSN_TLB);
5114 //erase_all(core, INSN_TLB);
5115 break;
5116 case 1: /* invalidate by MVA */
5117 //invalidate_by_mva(state, value);
5118 //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by mva\n");
5119 //remove_tlb_by_mva(RD, INSN_TLB);
5120 //erase_by_mva(core, RD, INSN_TLB);
5121 break;
5122 case 2: /* invalidate by asid */
5123 //invalidate_by_asid(state, value);
5124 //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by asid\n");
5125 //erase_by_asid(core, RD, INSN_TLB);
5126 break;
5127 default:
5128 break;
5129 }
5130
5131 break;
5132 case 6: /* DTLB */
5133 switch(OPCODE_2){
5134 case 0: /* invalidate all */
5135 //invalidate_all_tlb(state);
5136 //remove_tlb(DATA_TLB);
5137 //erase_all(core, DATA_TLB);
5138 DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate all\n");
5139 break;
5140 case 1: /* invalidate by MVA */
5141 //invalidate_by_mva(state, value);
5142 //remove_tlb_by_mva(RD, DATA_TLB);
5143 //erase_by_mva(core, RD, DATA_TLB);
5144 //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by mva\n");
5145 break;
5146 case 2: /* invalidate by asid */
5147 //invalidate_by_asid(state, value);
5148 //remove_tlb_by_asid(RD, DATA_TLB);
5149 //erase_by_asid(core, RD, DATA_TLB);
5150 //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by asid\n");
5151 break;
5152 default:
5153 break;
5154 }
5155 break;
5156 case 7: /* UNIFILED TLB */
5157 switch(OPCODE_2){
5158 case 0: /* invalidate all */
5159 //invalidate_all_tlb(state);
5160 //erase_all(core, INSN_TLB);
5161 //erase_all(core, DATA_TLB);
5162 //remove_tlb(DATA_TLB);
5163 //remove_tlb(INSN_TLB);
5164 //DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate all\n");
5165 break;
5166 case 1: /* invalidate by MVA */
5167 //invalidate_by_mva(state, value);
5168 //erase_by_mva(core, RD, DATA_TLB);
5169 //erase_by_mva(core, RD, INSN_TLB);
5170 DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by mva\n");
5171 break;
5172 case 2: /* invalidate by asid */
5173 //invalidate_by_asid(state, value);
5174 //erase_by_asid(core, RD, DATA_TLB);
5175 //erase_by_asid(core, RD, INSN_TLB);
5176 DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by asid\n");
5177 break;
5178 default:
5179 break;
5180 }
5181 break;
5182 default:
5183 break;
5184 }
5185 } else if(CRn == MMU_PID){
5186 if(OPCODE_2 == 0)
5187 CP15_REG(CP15_PID) = RD;
5188 else if(OPCODE_2 == 1)
5189 CP15_REG(CP15_CONTEXT_ID) = RD;
5190 else if(OPCODE_2 == 3){
5191 CP15_REG(CP15_THREAD_URO) = RD;
5192 }
5193 else{
5194 printf ("mmu_mcr wrote UNKNOWN - reg %d\n", CRn);
5195 }
5196
5197 } else {
5198 DEBUG_LOG(ARM11, "mcr is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2);
5199 }
5200 }
5201 }
5202 }
5203 cpu->Reg[15] += GET_INST_SIZE(cpu);
5204 INC_PC(sizeof(mcr_inst));
5205 FETCH_INST;
5206 GOTO_NEXT_INST;
5207 }
5208 MCRR_INST:
5209 MLA_INST:
5210 {
5211 INC_ICOUNTER;
5212 mla_inst *inst_cream = (mla_inst *)inst_base->component;
5213 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5214 uint64_t rm = RM;
5215 uint64_t rs = RS;
5216 uint64_t rn = RN;
5217 if (inst_cream->Rm == 15 || inst_cream->Rs == 15 || inst_cream->Rn == 15) {
5218 DEBUG_LOG(ARM11, "in __line__\n", __LINE__);
5219 CITRA_IGNORE_EXIT(-1);
5220 }
5221// RD = dst = RM * RS + RN;
5222 RD = dst = static_cast<uint32_t>((rm * rs + rn) & 0xffffffff);
5223 if (inst_cream->S) {
5224 UPDATE_NFLAG(dst);
5225 UPDATE_ZFLAG(dst);
5226 }
5227 if (inst_cream->Rd == 15) {
5228 INC_PC(sizeof(mla_inst));
5229 goto DISPATCH;
5230 }
5231 }
5232 cpu->Reg[15] += GET_INST_SIZE(cpu);
5233 INC_PC(sizeof(mla_inst));
5234 FETCH_INST;
5235 GOTO_NEXT_INST;
5236 }
5237 MOV_INST:
5238 {
5239// DEBUG_LOG(ARM11, "mov inst\n");
5240// DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]);
5241// debug_function(cpu);
5242// cpu->icount ++;
5243 INC_ICOUNTER;
5244 mov_inst *inst_cream = (mov_inst *)inst_base->component;
5245 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5246 RD = dst = SHIFTER_OPERAND;
5247 if (inst_cream->S && (inst_cream->Rd == 15)) {
5248 /* cpsr = spsr */
5249 if (CurrentModeHasSPSR) {
5250 cpu->Cpsr = cpu->Spsr_copy;
5251 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5252 LOAD_NZCVT;
5253 }
5254 } else if (inst_cream->S) {
5255 UPDATE_NFLAG(dst);
5256 UPDATE_ZFLAG(dst);
5257 UPDATE_CFLAG_WITH_SC;
5258 }
5259 if (inst_cream->Rd == 15) {
5260 INC_PC(sizeof(mov_inst));
5261 goto DISPATCH;
5262 }
5263// return;
5264 }
5265 cpu->Reg[15] += GET_INST_SIZE(cpu);
5266 INC_PC(sizeof(mov_inst));
5267 FETCH_INST;
5268 GOTO_NEXT_INST;
5269 }
5270 MRC_INST:
5271 {
5272 INC_ICOUNTER;
5273 /* NOT IMPL */
5274 mrc_inst *inst_cream = (mrc_inst *)inst_base->component;
5275 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5276 unsigned int inst = inst_cream->inst;
5277 if (inst_cream->Rd == 15) {
5278 DEBUG_MSG;
5279 }
5280 if (inst_cream->inst == 0xeef04a10) {
5281 /* undefined instruction fmrx */
5282 RD = 0x20000000;
5283 CITRA_IGNORE_EXIT(-1);
5284 goto END;
5285 } else {
5286 if (inst_cream->cp_num == 15) {
5287 if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) {
5288 //LET(RD, CONST(0x0007b000));
5289 //LET(RD, CONST(0x410FB760));
5290 //LET(RD, R(CP15_MAIN_ID));
5291 RD = cpu->CP15[CP15(CP15_MAIN_ID)];
5292 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
5293 //LET(RD, R(CP15_CONTROL));
5294 RD = cpu->CP15[CP15(CP15_CONTROL)];
5295 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
5296 //LET(RD, R(CP15_CONTROL));
5297 RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)];
5298 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
5299 //LET(RD, R(CP15_CONTROL));
5300 RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)];
5301 } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
5302 //LET(RD, R(CP15_DOMAIN_ACCESS_CONTROL));
5303 RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)];
5304 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
5305 //LET(RD, R(CP15_TRANSLATION_BASE_TABLE_0));
5306 RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)];
5307 } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) {
5308 //LET(RD, R(CP15_FAULT_STATUS));
5309 RD = cpu->CP15[CP15(CP15_FAULT_STATUS)];
5310 } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) {
5311 //LET(RD, R(CP15_FAULT_ADDRESS));
5312 RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)];
5313 } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) {
5314 //LET(RD, R(CP15_CACHE_TYPE));
5315 RD = cpu->CP15[CP15(CP15_CACHE_TYPE)];
5316 } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) {
5317 //LET(RD, R(CP15_INSTR_FAULT_STATUS));
5318 RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)];
5319 } else if (CRn == 13) {
5320 if(OPCODE_2 == 0)
5321 RD = CP15_REG(CP15_PID);
5322 else if(OPCODE_2 == 1)
5323 RD = CP15_REG(CP15_CONTEXT_ID);
5324 else if(OPCODE_2 == 3){
5325 RD = Memory::KERNEL_MEMORY_VADDR;
5326 }
5327 else{
5328 printf ("mmu_mrr wrote UNKNOWN - reg %d\n", CRn);
5329 }
5330 }
5331 else {
5332 DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2);
5333 }
5334 }
5335 //DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2);
5336 }
5337 }
5338 cpu->Reg[15] += GET_INST_SIZE(cpu);
5339 INC_PC(sizeof(mrc_inst));
5340 FETCH_INST;
5341 GOTO_NEXT_INST;
5342 }
5343 MRRC_INST:
5344 MRS_INST:
5345 {
5346 INC_ICOUNTER;
5347 mrs_inst *inst_cream = (mrs_inst *)inst_base->component;
5348 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5349 if (inst_cream->R) {
5350 RD = cpu->Spsr_copy;
5351 } else {
5352 SAVE_NZCVT;
5353 RD = cpu->Cpsr;
5354 }
5355 }
5356 cpu->Reg[15] += GET_INST_SIZE(cpu);
5357 INC_PC(sizeof(mrs_inst));
5358 FETCH_INST;
5359 GOTO_NEXT_INST;
5360 }
5361 MSR_INST:
5362 {
5363 INC_ICOUNTER;
5364 msr_inst *inst_cream = (msr_inst *)inst_base->component;
5365 const uint32_t UnallocMask = 0x06f0fc00, UserMask = 0xf80f0200, PrivMask = 0x000001df, StateMask = 0x01000020;
5366 unsigned int inst = inst_cream->inst;
5367 unsigned int operand;
5368
5369 if (BIT(inst, 25)) {
5370 int rot_imm = BITS(inst, 8, 11) * 2;
5371 //operand = ROTL(CONST(BITS(0, 7)), CONST(32 - rot_imm));
5372 operand = ROTATE_RIGHT_32(BITS(inst, 0, 7), rot_imm);
5373 } else {
5374 //operand = R(RM);
5375 operand = cpu->Reg[BITS(inst, 0, 3)];
5376 }
5377 uint32_t byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0)
5378 | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0);
5379 uint32_t mask;
5380 if (!inst_cream->R) {
5381 if (InAPrivilegedMode(cpu)) {
5382 if ((operand & StateMask) != 0) {
5383 /* UNPREDICTABLE */
5384 DEBUG_MSG;
5385 } else
5386 mask = byte_mask & (UserMask | PrivMask);
5387 } else {
5388 mask = byte_mask & UserMask;
5389 }
5390 //LET(CPSR_REG, OR(AND(R(CPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask))));
5391 SAVE_NZCVT;
5392
5393 cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask);
5394 switch_mode(cpu, cpu->Cpsr & 0x1f);
5395 LOAD_NZCVT;
5396 } else {
5397 if (CurrentModeHasSPSR) {
5398 mask = byte_mask & (UserMask | PrivMask | StateMask);
5399 //LET(SPSR_REG, OR(AND(R(SPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask))));
5400 cpu->Spsr_copy = (cpu->Spsr_copy & ~mask) | (operand & mask);
5401 }
5402 }
5403 cpu->Reg[15] += GET_INST_SIZE(cpu);
5404 INC_PC(sizeof(msr_inst));
5405 FETCH_INST;
5406 GOTO_NEXT_INST;
5407 }
5408 MUL_INST:
5409 {
5410 INC_ICOUNTER;
5411 mul_inst *inst_cream = (mul_inst *)inst_base->component;
5412 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5413// RD = dst = SHIFTER_OPERAND;
5414 uint64_t rm = RM;
5415 uint64_t rs = RS;
5416 RD = dst = static_cast<uint32_t>((rm * rs) & 0xffffffff);
5417 if (inst_cream->S) {
5418 UPDATE_NFLAG(dst);
5419 UPDATE_ZFLAG(dst);
5420 }
5421 if (inst_cream->Rd == 15) {
5422 INC_PC(sizeof(mul_inst));
5423 goto DISPATCH;
5424 }
5425 }
5426 cpu->Reg[15] += GET_INST_SIZE(cpu);
5427 INC_PC(sizeof(mul_inst));
5428 FETCH_INST;
5429 GOTO_NEXT_INST;
5430 }
5431 MVN_INST:
5432 {
5433 INC_ICOUNTER;
5434 mvn_inst *inst_cream = (mvn_inst *)inst_base->component;
5435 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5436// RD = dst = (SHIFTER_OPERAND ^ 0xffffffff);
5437 RD = dst = ~SHIFTER_OPERAND;
5438 if (inst_cream->S && (inst_cream->Rd == 15)) {
5439 /* cpsr = spsr */
5440 if (CurrentModeHasSPSR) {
5441 cpu->Cpsr = cpu->Spsr_copy;
5442 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5443 LOAD_NZCVT;
5444 }
5445 } else if (inst_cream->S) {
5446 UPDATE_NFLAG(dst);
5447 UPDATE_ZFLAG(dst);
5448 UPDATE_CFLAG_WITH_SC;
5449 }
5450 if (inst_cream->Rd == 15) {
5451 INC_PC(sizeof(mvn_inst));
5452 goto DISPATCH;
5453 }
5454 }
5455 cpu->Reg[15] += GET_INST_SIZE(cpu);
5456 INC_PC(sizeof(mvn_inst));
5457 FETCH_INST;
5458 GOTO_NEXT_INST;
5459 }
5460 ORR_INST:
5461 {
5462 INC_ICOUNTER;
5463 orr_inst *inst_cream = (orr_inst *)inst_base->component;
5464 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5465 lop = RN;
5466 rop = SHIFTER_OPERAND;
5467// DEBUG_LOG(ARM11, "lop is %x, rop is %x, r2 is %x, r3 is %x\n", lop, rop, cpu->Reg[2], cpu->Reg[3]);
5468 RD = dst = lop | rop;
5469 if (inst_cream->S && (inst_cream->Rd == 15)) {
5470 /* cpsr = spsr*/
5471 if (CurrentModeHasSPSR) {
5472 cpu->Cpsr = cpu->Spsr_copy;
5473 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5474 LOAD_NZCVT;
5475 }
5476 } else if (inst_cream->S) {
5477 UPDATE_NFLAG(dst);
5478 UPDATE_ZFLAG(dst);
5479 UPDATE_CFLAG_WITH_SC;
5480// UPDATE_CFLAG(dst, lop, rop);
5481 }
5482 if (inst_cream->Rd == 15) {
5483 INC_PC(sizeof(orr_inst));
5484 goto DISPATCH;
5485 }
5486 }
5487 cpu->Reg[15] += GET_INST_SIZE(cpu);
5488 INC_PC(sizeof(orr_inst));
5489 FETCH_INST;
5490 GOTO_NEXT_INST;
5491 }
5492 PKHBT_INST:
5493 PKHTB_INST:
5494 PLD_INST:
5495 {
5496 INC_ICOUNTER;
5497 /* NOT IMPL */
5498 cpu->Reg[15] += GET_INST_SIZE(cpu);
5499 INC_PC(sizeof(stc_inst));
5500 FETCH_INST;
5501 GOTO_NEXT_INST;
5502 }
5503 QADD_INST:
5504 QADD16_INST:
5505 QADD8_INST:
5506 QADDSUBX_INST:
5507 QDADD_INST:
5508 QDSUB_INST:
5509 QSUB_INST:
5510 QSUB16_INST:
5511 QSUB8_INST:
5512 QSUBADDX_INST:
5513 REV_INST:
5514 {
5515 INC_ICOUNTER;
5516 rev_inst *inst_cream = (rev_inst *)inst_base->component;
5517 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5518 RD = ((RM & 0xff) << 24) |
5519 (((RM >> 8) & 0xff) << 16) |
5520 (((RM >> 16) & 0xff) << 8) |
5521 ((RM >> 24) & 0xff);
5522 if (inst_cream->Rm == 15) {
5523 DEBUG_LOG(ARM11, "in line %d\n", __LINE__);
5524 CITRA_IGNORE_EXIT(-1);
5525 }
5526 }
5527 cpu->Reg[15] += GET_INST_SIZE(cpu);
5528 INC_PC(sizeof(rev_inst));
5529 FETCH_INST;
5530 GOTO_NEXT_INST;
5531 }
5532 REV16_INST:
5533 {
5534 INC_ICOUNTER;
5535 rev_inst *inst_cream = (rev_inst *)inst_base->component;
5536 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5537 RD = (BITS(RM, 0, 7) << 8) |
5538 BITS(RM, 8, 15) |
5539 (BITS(RM, 16, 23) << 24) |
5540 (BITS(RM, 24, 31) << 16);
5541 }
5542 cpu->Reg[15] += GET_INST_SIZE(cpu);
5543 INC_PC(sizeof(rev_inst));
5544 FETCH_INST;
5545 GOTO_NEXT_INST;
5546 }
5547 REVSH_INST:
5548 RFE_INST:
5549 RSB_INST:
5550 {
5551 INC_ICOUNTER;
5552 rsb_inst *inst_cream = (rsb_inst *)inst_base->component;
5553 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5554 rop = RN;
5555 lop = SHIFTER_OPERAND;
5556 if (inst_cream->Rn == 15) {
5557 rop += 2 * GET_INST_SIZE(cpu);;
5558 }
5559 RD = dst = lop - rop;
5560 if (inst_cream->S && (inst_cream->Rd == 15)) {
5561 /* cpsr = spsr */
5562 if (CurrentModeHasSPSR) {
5563 cpu->Cpsr = cpu->Spsr_copy;
5564 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5565 LOAD_NZCVT;
5566 }
5567 } else if (inst_cream->S) {
5568 UPDATE_NFLAG(dst);
5569 UPDATE_ZFLAG(dst);
5570 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
5571// UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
5572 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
5573 }
5574 if (inst_cream->Rd == 15) {
5575 INC_PC(sizeof(rsb_inst));
5576 goto DISPATCH;
5577 }
5578 }
5579 cpu->Reg[15] += GET_INST_SIZE(cpu);
5580 INC_PC(sizeof(rsb_inst));
5581 FETCH_INST;
5582 GOTO_NEXT_INST;
5583 }
5584 RSC_INST:
5585 {
5586 INC_ICOUNTER;
5587 rsc_inst *inst_cream = (rsc_inst *)inst_base->component;
5588 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5589 //lop = RN + !cpu->CFlag;
5590 //rop = SHIFTER_OPERAND;
5591 //RD = dst = rop - lop;
5592 lop = RN;
5593 rop = SHIFTER_OPERAND;
5594 RD = dst = rop - lop - !cpu->CFlag;
5595 if (inst_cream->S && (inst_cream->Rd == 15)) {
5596 /* cpsr = spsr */
5597 if (CurrentModeHasSPSR) {
5598 cpu->Cpsr = cpu->Spsr_copy;
5599 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5600 LOAD_NZCVT;
5601 }
5602 } else if (inst_cream->S) {
5603 UPDATE_NFLAG(dst);
5604 UPDATE_ZFLAG(dst);
5605// UPDATE_CFLAG(dst, lop, rop);
5606// UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop);
5607 UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(rop, lop, !cpu->CFlag);
5608// cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst)));
5609 UPDATE_VFLAG_OVERFLOW_FROM((int)dst, (int)rop, (int)lop);
5610 }
5611 if (inst_cream->Rd == 15) {
5612 INC_PC(sizeof(rsc_inst));
5613 goto DISPATCH;
5614 }
5615 }
5616 cpu->Reg[15] += GET_INST_SIZE(cpu);
5617 INC_PC(sizeof(rsc_inst));
5618 FETCH_INST;
5619 GOTO_NEXT_INST;
5620 }
5621 SADD16_INST:
5622 SADD8_INST:
5623 SADDSUBX_INST:
5624 SBC_INST:
5625 {
5626 INC_ICOUNTER;
5627 sbc_inst *inst_cream = (sbc_inst *)inst_base->component;
5628 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5629 lop = SHIFTER_OPERAND + !cpu->CFlag;
5630 rop = RN;
5631 RD = dst = rop - lop;
5632 if (inst_cream->S && (inst_cream->Rd == 15)) {
5633 /* cpsr = spsr */
5634 if (CurrentModeHasSPSR) {
5635 cpu->Cpsr = cpu->Spsr_copy;
5636 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5637 LOAD_NZCVT;
5638 }
5639 } else if (inst_cream->S) {
5640 UPDATE_NFLAG(dst);
5641 UPDATE_ZFLAG(dst);
5642// UPDATE_CFLAG(dst, lop, rop);
5643 //UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop);
5644 //rop = rop - !cpu->CFlag;
5645 if(rop >= !cpu->CFlag)
5646 UPDATE_CFLAG_NOT_BORROW_FROM(rop - !cpu->CFlag, SHIFTER_OPERAND);
5647 else
5648 UPDATE_CFLAG_NOT_BORROW_FROM(rop, !cpu->CFlag);
5649// cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst)));
5650 UPDATE_VFLAG_OVERFLOW_FROM(dst, rop, lop);
5651 }
5652 if (inst_cream->Rd == 15) {
5653 INC_PC(sizeof(sbc_inst));
5654 goto DISPATCH;
5655 }
5656 }
5657 cpu->Reg[15] += GET_INST_SIZE(cpu);
5658 INC_PC(sizeof(sbc_inst));
5659 FETCH_INST;
5660 GOTO_NEXT_INST;
5661 }
5662 SEL_INST:
5663 SETEND_INST:
5664 SHADD16_INST:
5665 SHADD8_INST:
5666 SHADDSUBX_INST:
5667 SHSUB16_INST:
5668 SHSUB8_INST:
5669 SHSUBADDX_INST:
5670 SMLA_INST:
5671 {
5672 INC_ICOUNTER;
5673 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5674 smla_inst *inst_cream = (smla_inst *)inst_base->component;
5675 int32_t operand1, operand2;
5676 if (inst_cream->x == 0)
5677 operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15);
5678 else
5679 operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31);
5680
5681 if (inst_cream->y == 0)
5682 operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15);
5683 else
5684 operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
5685 RD = operand1 * operand2 + RN;
5686 //FIXME: UPDATE Q FLAGS
5687 }
5688 cpu->Reg[15] += GET_INST_SIZE(cpu);
5689 INC_PC(sizeof(smla_inst));
5690 FETCH_INST;
5691 GOTO_NEXT_INST;
5692 }
5693 SMLAD_INST:
5694 {
5695 INC_ICOUNTER;
5696 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5697 smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
5698 long long int rm = cpu->Reg[inst_cream->Rm];
5699 long long int rn = cpu->Reg[inst_cream->Rn];
5700 long long int ra = cpu->Reg[inst_cream->Ra];
5701 /* see SMUAD */
5702 if(inst_cream->Ra == 15)
5703 CITRA_IGNORE_EXIT(-1);
5704 int operand2 = (inst_cream->m)? ROTATE_RIGHT_32(rm, 16):rm;
5705
5706 int half_rn, half_operand2;
5707 half_rn = rn & 0xFFFF;
5708 half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn;
5709
5710 half_operand2 = operand2 & 0xFFFF;
5711 half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2;
5712
5713 long long int product1 = half_rn * half_operand2;
5714
5715 half_rn = (rn & 0xFFFF0000) >> 16;
5716 half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn;
5717
5718 half_operand2 = (operand2 & 0xFFFF0000) >> 16;
5719 half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2;
5720
5721 long long int product2 = half_rn * half_operand2;
5722
5723 long long int signed_ra = (ra & 0x80000000)? (0xFFFFFFFF00000000LL) | ra : ra;
5724 long long int result = product1 + product2 + signed_ra;
5725 cpu->Reg[inst_cream->Rd] = result & 0xFFFFFFFF;
5726 /* FIXME , should check Signed overflow */
5727 }
5728 cpu->Reg[15] += GET_INST_SIZE(cpu);
5729 INC_PC(sizeof(umlal_inst));
5730 FETCH_INST;
5731 GOTO_NEXT_INST;
5732 }
5733
5734 SMLAL_INST:
5735 {
5736 INC_ICOUNTER;
5737 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5738 umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
5739 long long int rm = RM;
5740 long long int rs = RS;
5741 if (BIT(rm, 31)) {
5742 rm |= 0xffffffff00000000LL;
5743 }
5744 if (BIT(rs, 31)) {
5745 rs |= 0xffffffff00000000LL;
5746 }
5747 long long int rst = rm * rs;
5748 long long int rdhi32 = RDHI;
5749 long long int hilo = (rdhi32 << 32) + RDLO;
5750 rst += hilo;
5751 RDLO = BITS(rst, 0, 31);
5752 RDHI = BITS(rst, 32, 63);
5753 if (inst_cream->S) {
5754 cpu->NFlag = BIT(RDHI, 31);
5755 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
5756 }
5757 }
5758 cpu->Reg[15] += GET_INST_SIZE(cpu);
5759 INC_PC(sizeof(umlal_inst));
5760 FETCH_INST;
5761 GOTO_NEXT_INST;
5762 }
5763 SMLALXY_INST:
5764 SMLALD_INST:
5765 SMLAW_INST:
5766 SMLSD_INST:
5767 SMLSLD_INST:
5768 SMMLA_INST:
5769 SMMLS_INST:
5770 SMMUL_INST:
5771 SMUAD_INST:
5772 SMUL_INST:
5773 {
5774 INC_ICOUNTER;
5775 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5776 smul_inst *inst_cream = (smul_inst *)inst_base->component;
5777 uint32_t operand1, operand2;
5778 if (inst_cream->x == 0)
5779 operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15);
5780 else
5781 operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31);
5782
5783 if (inst_cream->y == 0)
5784 operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15);
5785 else
5786 operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
5787 RD = operand1 * operand2;
5788 }
5789 cpu->Reg[15] += GET_INST_SIZE(cpu);
5790 INC_PC(sizeof(smul_inst));
5791 FETCH_INST;
5792 GOTO_NEXT_INST;
5793 }
5794 SMULL_INST:
5795 {
5796 INC_ICOUNTER;
5797 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5798 umull_inst *inst_cream = (umull_inst *)inst_base->component;
5799// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst);
5800 int64_t rm = RM;
5801 int64_t rs = RS;
5802 if (BIT(rm, 31)) {
5803 rm |= 0xffffffff00000000LL;
5804 }
5805 if (BIT(rs, 31)) {
5806 rs |= 0xffffffff00000000LL;
5807 }
5808 int64_t rst = rm * rs;
5809 RDHI = BITS(rst, 32, 63);
5810 RDLO = BITS(rst, 0, 31);
5811
5812
5813 if (inst_cream->S) {
5814 cpu->NFlag = BIT(RDHI, 31);
5815 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
5816 }
5817 }
5818 cpu->Reg[15] += GET_INST_SIZE(cpu);
5819 INC_PC(sizeof(umull_inst));
5820 FETCH_INST;
5821 GOTO_NEXT_INST;
5822 }
5823 SMULW_INST:
5824 INC_ICOUNTER;
5825 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5826 smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
5827// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst);
5828 int64_t rm = RM;
5829 int64_t rn = RN;
5830 if (inst_cream->m)
5831 rm = BITS(rm,16 , 31);
5832 else
5833 rm = BITS(rm,0 , 15);
5834 int64_t rst = rm * rn;
5835 RD = BITS(rst, 16, 47);
5836 }
5837 cpu->Reg[15] += GET_INST_SIZE(cpu);
5838 INC_PC(sizeof(smlad_inst));
5839 FETCH_INST;
5840 GOTO_NEXT_INST;
5841
5842 SMUSD_INST:
5843 SRS_INST:
5844 SSAT_INST:
5845 SSAT16_INST:
5846 SSUB16_INST:
5847 SSUB8_INST:
5848 SSUBADDX_INST:
5849 STC_INST:
5850 {
5851 INC_ICOUNTER;
5852 /* NOT IMPL */
5853 cpu->Reg[15] += GET_INST_SIZE(cpu);
5854 INC_PC(sizeof(stc_inst));
5855 FETCH_INST;
5856 GOTO_NEXT_INST;
5857 }
5858 STM_INST:
5859 {
5860 INC_ICOUNTER;
5861 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5862 unsigned int inst = inst_cream->inst;
5863 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5864 int i;
5865 unsigned int Rn = BITS(inst, 16, 19);
5866 unsigned int old_RN = cpu->Reg[Rn];
5867
5868 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
5869 if (fault) goto MMU_EXCEPTION;
5870 if (BIT(inst_cream->inst, 22) == 1) {
5871// DEBUG_MSG;
5872 #if 1
5873 for (i = 0; i < 13; i++) {
5874 if(BIT(inst_cream->inst, i)){
5875 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5876 if (fault) {
5877 goto MMU_EXCEPTION;
5878 }
5879 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
5880 if (fault) goto MMU_EXCEPTION;
5881 addr += 4;
5882 phys_addr += 4;
5883 }
5884 }
5885 if (BIT(inst_cream->inst, 13)) {
5886 if (cpu->Mode == USER32MODE) {
5887 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5888 if (fault) {
5889 goto MMU_EXCEPTION;
5890 }
5891 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
5892 if (fault) goto MMU_EXCEPTION;
5893 addr += 4;
5894 phys_addr += 4;
5895 } else {
5896 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[0], 32);
5897 if (fault) goto MMU_EXCEPTION;
5898 addr += 4;
5899 phys_addr += 4;
5900 }
5901 }
5902 if (BIT(inst_cream->inst, 14)) {
5903 if (cpu->Mode == USER32MODE) {
5904 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5905 if (fault) {
5906 goto MMU_EXCEPTION;
5907 }
5908 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
5909 if (fault) goto MMU_EXCEPTION;
5910 addr += 4;
5911 phys_addr += 4;
5912 } else {
5913 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5914 if (fault) {
5915 goto MMU_EXCEPTION;
5916 }
5917 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[1], 32);
5918 if (fault) goto MMU_EXCEPTION;
5919 addr += 4;
5920 phys_addr += 4;
5921 }
5922 }
5923 if (BIT(inst_cream->inst, 15)) {
5924 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5925 if (fault) {
5926 goto MMU_EXCEPTION;
5927 }
5928 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32);
5929 if (fault) goto MMU_EXCEPTION;
5930 }
5931 #endif
5932 } else {
5933 for( i = 0; i < 15; i ++ ){
5934 if(BIT(inst_cream->inst, i)){
5935 //arch_write_memory(cpu, bb, Addr, R(i), 32);
5936 //bus_write(32, addr, cpu->Reg[i]);
5937 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5938 if (fault) {
5939 goto MMU_EXCEPTION;
5940 }
5941 if(i == Rn)
5942 fault = interpreter_write_memory(addr, phys_addr, old_RN, 32);
5943 else
5944 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
5945 if (fault) goto MMU_EXCEPTION;
5946 addr += 4;
5947 phys_addr += 4;
5948 //Addr = ADD(Addr, CONST(4));
5949 }
5950 }
5951
5952 /* check pc reg*/
5953 if(BIT(inst_cream->inst, i)){
5954 //arch_write_memory(cpu, bb, Addr, STOREM_CHECK_PC, 32);
5955 //bus_write(32, addr, cpu->Reg[i] + 8);
5956 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5957 if (fault) {
5958 goto MMU_EXCEPTION;
5959 }
5960 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32);
5961 if (fault) goto MMU_EXCEPTION;
5962 }
5963 }
5964 }
5965 cpu->Reg[15] += GET_INST_SIZE(cpu);
5966 INC_PC(sizeof(ldst_inst));
5967 FETCH_INST;
5968 GOTO_NEXT_INST;
5969 }
5970 SXTB_INST:
5971 {
5972 INC_ICOUNTER;
5973 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
5974 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5975 if (inst_cream->Rm == 15) {
5976 DEBUG_LOG(ARM11, "line is %d\n", __LINE__);
5977 CITRA_IGNORE_EXIT(-1);
5978 }
5979 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
5980 if (BIT(operand2, 7)) {
5981 operand2 |= 0xffffff00;
5982 } else
5983 operand2 &= 0xff;
5984 RD = operand2;
5985 }
5986 cpu->Reg[15] += GET_INST_SIZE(cpu);
5987 INC_PC(sizeof(sxtb_inst));
5988 FETCH_INST;
5989 GOTO_NEXT_INST;
5990 }
5991 STR_INST:
5992 {
5993 INC_ICOUNTER;
5994 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5995 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5996 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
5997 if (fault) goto MMU_EXCEPTION;
5998 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
5999 //bus_write(32, addr, value);
6000 fault = interpreter_write_memory(addr, phys_addr, value, 32);
6001 if (fault) goto MMU_EXCEPTION;
6002 }
6003 cpu->Reg[15] += GET_INST_SIZE(cpu);
6004 INC_PC(sizeof(ldst_inst));
6005 FETCH_INST;
6006 GOTO_NEXT_INST;
6007 }
6008 UXTB_INST:
6009 {
6010 INC_ICOUNTER;
6011 uxtb_inst *inst_cream = (uxtb_inst *)inst_base->component;
6012 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6013 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
6014 & 0xff;
6015 RD = operand2;
6016 }
6017 cpu->Reg[15] += GET_INST_SIZE(cpu);
6018 INC_PC(sizeof(uxtb_inst));
6019 FETCH_INST;
6020 GOTO_NEXT_INST;
6021 }
6022 UXTAB_INST:
6023 {
6024 INC_ICOUNTER;
6025 uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component;
6026 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6027 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
6028 & 0xff;
6029 RD = RN + operand2;
6030 }
6031 cpu->Reg[15] += GET_INST_SIZE(cpu);
6032 INC_PC(sizeof(uxtab_inst));
6033 FETCH_INST;
6034 GOTO_NEXT_INST;
6035 }
6036 STRB_INST:
6037 {
6038 INC_ICOUNTER;
6039 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6040 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6041 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
6042 if (fault) goto MMU_EXCEPTION;
6043 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
6044 //bus_write(8, addr, value);
6045 fault = interpreter_write_memory(addr, phys_addr, value, 8);
6046 if (fault) goto MMU_EXCEPTION;
6047 }
6048 cpu->Reg[15] += GET_INST_SIZE(cpu);
6049 INC_PC(sizeof(ldst_inst));
6050 FETCH_INST;
6051 GOTO_NEXT_INST;
6052 }
6053 STRBT_INST:
6054 {
6055 INC_ICOUNTER;
6056 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6057 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6058 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
6059 if (fault) goto MMU_EXCEPTION;
6060 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
6061 //bus_write(8, addr, value);
6062 fault = interpreter_write_memory(addr, phys_addr, value, 8);
6063 if (fault) goto MMU_EXCEPTION;
6064 }
6065 cpu->Reg[15] += GET_INST_SIZE(cpu);
6066 //if (BITS(inst_cream->inst, 12, 15) == 15)
6067 // goto DISPATCH;
6068 INC_PC(sizeof(ldst_inst));
6069 FETCH_INST;
6070 GOTO_NEXT_INST;
6071 }
6072 STRD_INST:
6073 {
6074 INC_ICOUNTER;
6075 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6076 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6077 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
6078 if (fault) goto MMU_EXCEPTION;
6079 uint32_t rear_phys_addr;
6080 fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 0);
6081 if (fault){
6082 ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n");
6083 CITRA_IGNORE_EXIT(-1);
6084 goto MMU_EXCEPTION;
6085 }
6086
6087 //fault = inst_cream->get_addr(cpu, inst_cream->inst, addr + 4, phys_addr + 4, 0);
6088 //if (fault) goto MMU_EXCEPTION;
6089
6090 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
6091 //bus_write(32, addr, value);
6092 fault = interpreter_write_memory(addr, phys_addr, value, 32);
6093 if (fault) goto MMU_EXCEPTION;
6094 value = cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1];
6095 //bus_write(32, addr, value);
6096 fault = interpreter_write_memory(addr + 4, rear_phys_addr, value, 32);
6097 if (fault) goto MMU_EXCEPTION;
6098 }
6099 cpu->Reg[15] += GET_INST_SIZE(cpu);
6100 INC_PC(sizeof(ldst_inst));
6101 FETCH_INST;
6102 GOTO_NEXT_INST;
6103 }
6104 STREX_INST:
6105 {
6106 INC_ICOUNTER;
6107 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6108 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6109 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
6110 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)];
6111 fault = check_address_validity(cpu, addr, &phys_addr, 0);
6112 if (fault) goto MMU_EXCEPTION;
6113
6114 int dest_reg = BITS(inst_cream->inst, 12, 15);
6115 if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){
6116 remove_exclusive(cpu, phys_addr);
6117 cpu->Reg[dest_reg] = 0;
6118 cpu->exclusive_state = 0;
6119
6120 // bus_write(32, addr, value);
6121 fault = interpreter_write_memory(addr, phys_addr, value, 32);
6122 if (fault) goto MMU_EXCEPTION;
6123 }
6124 else{
6125 /* Failed to write due to mutex access */
6126 cpu->Reg[dest_reg] = 1;
6127 }
6128 }
6129 cpu->Reg[15] += GET_INST_SIZE(cpu);
6130 INC_PC(sizeof(ldst_inst));
6131 FETCH_INST;
6132 GOTO_NEXT_INST;
6133 }
6134 STREXB_INST:
6135 {
6136 INC_ICOUNTER;
6137 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6138 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6139 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
6140 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)] & 0xff;
6141 fault = check_address_validity(cpu, addr, &phys_addr, 0);
6142 if (fault) goto MMU_EXCEPTION;
6143 //bus_write(8, addr, value);
6144 int dest_reg = BITS(inst_cream->inst, 12, 15);
6145 if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){
6146 remove_exclusive(cpu, phys_addr);
6147 cpu->Reg[dest_reg] = 0;
6148 cpu->exclusive_state = 0;
6149 fault = interpreter_write_memory(addr, phys_addr, value, 8);
6150 if (fault) goto MMU_EXCEPTION;
6151
6152 }
6153 else{
6154 cpu->Reg[dest_reg] = 1;
6155 }
6156 }
6157 cpu->Reg[15] += GET_INST_SIZE(cpu);
6158 INC_PC(sizeof(ldst_inst));
6159 FETCH_INST;
6160 GOTO_NEXT_INST;
6161 }
6162 STRH_INST:
6163 {
6164 INC_ICOUNTER;
6165 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6166 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6167 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
6168 if (fault) goto MMU_EXCEPTION;
6169 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff;
6170 //bus_write(16, addr, value);
6171 fault = interpreter_write_memory(addr, phys_addr, value, 16);
6172 if (fault) goto MMU_EXCEPTION;
6173 }
6174 cpu->Reg[15] += GET_INST_SIZE(cpu);
6175 //if (BITS(inst_cream->inst, 12, 15) == 15)
6176 // goto DISPATCH;
6177 INC_PC(sizeof(ldst_inst));
6178 FETCH_INST;
6179 GOTO_NEXT_INST;
6180 }
6181 STRT_INST:
6182 {
6183 INC_ICOUNTER;
6184 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6185 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6186 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
6187 if (fault) goto MMU_EXCEPTION;
6188 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
6189 //bus_write(16, addr, value);
6190 fault = interpreter_write_memory(addr, phys_addr, value, 32);
6191 if (fault) goto MMU_EXCEPTION;
6192 }
6193 cpu->Reg[15] += GET_INST_SIZE(cpu);
6194 INC_PC(sizeof(ldst_inst));
6195 FETCH_INST;
6196 GOTO_NEXT_INST;
6197 }
6198 SUB_INST:
6199 {
6200 INC_ICOUNTER;
6201 sub_inst *inst_cream = (sub_inst *)inst_base->component;
6202 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6203 lop = RN;
6204 if (inst_cream->Rn == 15) {
6205 lop += 8;
6206 }
6207 rop = SHIFTER_OPERAND;
6208 RD = dst = lop - rop;
6209 if (inst_cream->S && (inst_cream->Rd == 15)) {
6210 /* cpsr = spsr */
6211 if (CurrentModeHasSPSR) {
6212 cpu->Cpsr = cpu->Spsr_copy;
6213 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
6214 LOAD_NZCVT;
6215 }
6216 } else if (inst_cream->S) {
6217 UPDATE_NFLAG(dst);
6218 UPDATE_ZFLAG(dst);
6219// UPDATE_CFLAG(dst, lop, rop);
6220 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
6221 // UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
6222 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
6223 }
6224 if (inst_cream->Rd == 15) {
6225 INC_PC(sizeof(sub_inst));
6226 goto DISPATCH;
6227 }
6228 }
6229 cpu->Reg[15] += GET_INST_SIZE(cpu);
6230 INC_PC(sizeof(sub_inst));
6231 FETCH_INST;
6232 GOTO_NEXT_INST;
6233 }
6234 SWI_INST:
6235 {
6236 INC_ICOUNTER;
6237 swi_inst *inst_cream = (swi_inst *)inst_base->component;
6238 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6239 if (true){ //if (core->is_user_mode) { --> Citra only emulates user mode
6240 //arm_dyncom_SWI(cpu, inst_cream->num);
6241 HLE::CallSVC(Memory::Read32(cpu->Reg[15]));
6242 } else {
6243 cpu->syscallSig = 1;
6244 goto END;
6245 }
6246 }
6247 cpu->Reg[15] += GET_INST_SIZE(cpu);
6248 INC_PC(sizeof(swi_inst));
6249 FETCH_INST;
6250 GOTO_NEXT_INST;
6251 }
6252 SWP_INST:
6253 {
6254 INC_ICOUNTER;
6255 swp_inst *inst_cream = (swp_inst *)inst_base->component;
6256 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6257 addr = RN;
6258 fault = check_address_validity(cpu, addr, &phys_addr, 1);
6259 if (fault) goto MMU_EXCEPTION;
6260 unsigned int value;
6261 fault = interpreter_read_memory(addr, phys_addr, value, 32);
6262 if (fault) goto MMU_EXCEPTION;
6263 fault = interpreter_write_memory(addr, phys_addr, RM, 32);
6264 if (fault) goto MMU_EXCEPTION;
6265
6266 /* ROR(data, 8*UInt(address<1:0>)); */
6267 assert((phys_addr & 0x3) == 0);
6268 RD = value;
6269 }
6270 cpu->Reg[15] += GET_INST_SIZE(cpu);
6271 INC_PC(sizeof(swp_inst));
6272 FETCH_INST;
6273 GOTO_NEXT_INST;
6274 }
6275 SWPB_INST:
6276 {
6277 INC_ICOUNTER;
6278 swp_inst *inst_cream = (swp_inst *)inst_base->component;
6279 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6280 addr = RN;
6281 fault = check_address_validity(cpu, addr, &phys_addr, 1);
6282 if (fault) goto MMU_EXCEPTION;
6283 unsigned int value;
6284 fault = interpreter_read_memory(addr, phys_addr, value, 8);
6285 if (fault) goto MMU_EXCEPTION;
6286 fault = interpreter_write_memory(addr, phys_addr, (RM & 0xFF), 8);
6287 if (fault) goto MMU_EXCEPTION;
6288
6289 /* FIXME */
6290 #if 0
6291 if Shared(address) then
6292 /* ARMv6 */
6293 physical_address = TLB(address)
6294 ClearExclusiveByAddress(physical_address,processor_id,1)
6295 /* See Summary of operation on page A2-49 */
6296 #endif
6297 }
6298 cpu->Reg[15] += GET_INST_SIZE(cpu);
6299 INC_PC(sizeof(swp_inst));
6300 FETCH_INST;
6301 GOTO_NEXT_INST;
6302 }
6303 SXTAB_INST:
6304 {
6305 INC_ICOUNTER;
6306 sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component;
6307 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6308 /* R15 should be check */
6309 if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){
6310 CITRA_IGNORE_EXIT(-1);
6311 }
6312 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
6313 & 0xff;
6314 /* sign extend for byte */
6315 operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2;
6316 RD = RN + operand2;
6317 }
6318 cpu->Reg[15] += GET_INST_SIZE(cpu);
6319 INC_PC(sizeof(uxtab_inst));
6320 FETCH_INST;
6321 GOTO_NEXT_INST;
6322 }
6323 SXTAB16_INST:
6324 SXTAH_INST:
6325 {
6326 INC_ICOUNTER;
6327 sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component;
6328 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6329 /* R15 should be check */
6330 if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){
6331 CITRA_IGNORE_EXIT(-1);
6332 }
6333 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff;
6334 /* sign extend for half */
6335 operand2 = (0x8000 & operand2)? (0xFFFF0000 | operand2):operand2;
6336 RD = RN + operand2;
6337 }
6338 cpu->Reg[15] += GET_INST_SIZE(cpu);
6339 INC_PC(sizeof(sxtah_inst));
6340 FETCH_INST;
6341 GOTO_NEXT_INST;
6342 }
6343 SXTB16_INST:
6344 TEQ_INST:
6345 {
6346 INC_ICOUNTER;
6347 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6348 teq_inst *inst_cream = (teq_inst *)inst_base->component;
6349 lop = RN;
6350 if (inst_cream->Rn == 15)
6351 lop += GET_INST_SIZE(cpu) * 2;
6352
6353 rop = SHIFTER_OPERAND;
6354 dst = lop ^ rop;
6355
6356 UPDATE_NFLAG(dst);
6357 UPDATE_ZFLAG(dst);
6358 UPDATE_CFLAG_WITH_SC;
6359 }
6360 cpu->Reg[15] += GET_INST_SIZE(cpu);
6361 INC_PC(sizeof(teq_inst));
6362 FETCH_INST;
6363 GOTO_NEXT_INST;
6364 }
6365 TST_INST:
6366 {
6367 INC_ICOUNTER;
6368 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6369 tst_inst *inst_cream = (tst_inst *)inst_base->component;
6370 lop = RN;
6371 if (inst_cream->Rn == 15)
6372 lop += GET_INST_SIZE(cpu) * 2;
6373 rop = SHIFTER_OPERAND;
6374 dst = lop & rop;
6375
6376 UPDATE_NFLAG(dst);
6377 UPDATE_ZFLAG(dst);
6378 UPDATE_CFLAG_WITH_SC;
6379 }
6380 cpu->Reg[15] += GET_INST_SIZE(cpu);
6381 INC_PC(sizeof(tst_inst));
6382 FETCH_INST;
6383 GOTO_NEXT_INST;
6384 }
6385 UADD16_INST:
6386 UADD8_INST:
6387 UADDSUBX_INST:
6388 UHADD16_INST:
6389 UHADD8_INST:
6390 UHADDSUBX_INST:
6391 UHSUB16_INST:
6392 UHSUB8_INST:
6393 UHSUBADDX_INST:
6394 UMAAL_INST:
6395 UMLAL_INST:
6396 {
6397 INC_ICOUNTER;
6398 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6399 umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
6400 unsigned long long int rm = RM;
6401 unsigned long long int rs = RS;
6402 unsigned long long int rst = rm * rs;
6403 unsigned long long int add = ((unsigned long long) RDHI)<<32;
6404 add += RDLO;
6405 //DEBUG_LOG(ARM11, "rm[%llx] * rs[%llx] = rst[%llx] | add[%llx]\n", RM, RS, rst, add);
6406 rst += add;
6407 RDLO = BITS(rst, 0, 31);
6408 RDHI = BITS(rst, 32, 63);
6409
6410 if (inst_cream->S)
6411 {
6412 cpu->NFlag = BIT(RDHI, 31);
6413 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
6414 }
6415 }
6416 cpu->Reg[15] += GET_INST_SIZE(cpu);
6417 INC_PC(sizeof(umlal_inst));
6418 FETCH_INST;
6419 GOTO_NEXT_INST;
6420 }
6421 UMULL_INST:
6422 {
6423 INC_ICOUNTER;
6424 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6425 umull_inst *inst_cream = (umull_inst *)inst_base->component;
6426 unsigned long long int rm = RM;
6427 unsigned long long int rs = RS;
6428 unsigned long long int rst = rm * rs;
6429// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst);
6430 RDHI = BITS(rst, 32, 63);
6431 RDLO = BITS(rst, 0, 31);
6432
6433 if (inst_cream->S) {
6434 cpu->NFlag = BIT(RDHI, 31);
6435 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
6436 }
6437 }
6438 cpu->Reg[15] += GET_INST_SIZE(cpu);
6439 INC_PC(sizeof(umull_inst));
6440 FETCH_INST;
6441 GOTO_NEXT_INST;
6442 }
6443 B_2_THUMB:
6444 {
6445 INC_ICOUNTER;
6446 b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component;
6447 cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
6448 //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]);
6449 INC_PC(sizeof(b_2_thumb));
6450 goto DISPATCH;
6451 }
6452 B_COND_THUMB:
6453 {
6454 INC_ICOUNTER;
6455 b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component;
6456 if(CondPassed(cpu, inst_cream->cond))
6457 cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
6458 else
6459 cpu->Reg[15] += 2;
6460 //DEBUG_LOG(ARM11, " B_COND_THUMB: imm=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[15]);
6461 INC_PC(sizeof(b_cond_thumb));
6462 goto DISPATCH;
6463 }
6464 BL_1_THUMB:
6465 {
6466 INC_ICOUNTER;
6467 bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component;
6468 cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm;
6469 //cpu->Reg[15] += 2;
6470 //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]);
6471
6472 cpu->Reg[15] += GET_INST_SIZE(cpu);
6473 INC_PC(sizeof(bl_1_thumb));
6474 FETCH_INST;
6475 GOTO_NEXT_INST;
6476
6477 }
6478 BL_2_THUMB:
6479 {
6480 INC_ICOUNTER;
6481 bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component;
6482 int tmp = ((cpu->Reg[15] + 2) | 1);
6483 cpu->Reg[15] =
6484 (cpu->Reg[14] + inst_cream->imm);
6485 cpu->Reg[14] = tmp;
6486 //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]);
6487 INC_PC(sizeof(bl_2_thumb));
6488 goto DISPATCH;
6489 }
6490 BLX_1_THUMB:
6491 {
6492 /* BLX 1 for armv5t and above */
6493 INC_ICOUNTER;
6494 uint32 tmp = cpu->Reg[15];
6495 blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component;
6496 cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm) & 0xFFFFFFFC;
6497 //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);
6498 cpu->Reg[14] = ((tmp + 2) | 1);
6499 //(state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC;
6500 /* switch to arm state from thumb state */
6501 cpu->TFlag = 0;
6502 //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]);
6503 INC_PC(sizeof(blx_1_thumb));
6504 goto DISPATCH;
6505 }
6506
6507 UQADD16_INST:
6508 UQADD8_INST:
6509 UQADDSUBX_INST:
6510 UQSUB16_INST:
6511 UQSUB8_INST:
6512 UQSUBADDX_INST:
6513 USAD8_INST:
6514 USADA8_INST:
6515 USAT_INST:
6516 USAT16_INST:
6517 USUB16_INST:
6518 USUB8_INST:
6519 USUBADDX_INST:
6520 UXTAB16_INST:
6521 UXTB16_INST:
6522 #define VFP_INTERPRETER_IMPL
6523 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
6524 #undef VFP_INTERPRETER_IMPL
6525 MMU_EXCEPTION:
6526 {
6527 SAVE_NZCVT;
6528 cpu->abortSig = true;
6529 cpu->Aborted = ARMul_DataAbortV;
6530 cpu->AbortAddr = addr;
6531 cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff;
6532 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
6533 cpu->NumInstrsToExecute = 0;
6534 return num_instrs;
6535 }
6536 END:
6537 {
6538 SAVE_NZCVT;
6539 cpu->NumInstrsToExecute = 0;
6540 return num_instrs;
6541 }
6542 INIT_INST_LENGTH:
6543 {
6544#if 0
6545 DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel));
6546 for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++)
6547 DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]);
6548 DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel));
6549#endif
6550#if defined __GNUC__ || defined __clang__
6551 InterpreterInitInstLength((unsigned long long int *)InstLabel, sizeof(InstLabel));
6552#endif
6553#if 0
6554 for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++)
6555 DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]);
6556 DEBUG_LOG(ARM11, "%llx\n", InstEndLabel[1]);
6557 DEBUG_LOG(ARM11, "%llx\n", InstLabel[1]);
6558 DEBUG_LOG(ARM11, "%lld\n", (char *)InstEndLabel[1] - (char *)InstLabel[1]);
6559#endif
6560 cpu->NumInstrsToExecute = 0;
6561 return num_instrs;
6562 }
6563}
6564
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7unsigned 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 @@
1/* Copyright (C)
2* 2011 - Michael.Kang blackfin.kang@gmail.com
3* This program is free software; you can redistribute it and/or
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18/**
19* @file arm_dyncom_run.cpp
20* @brief The dyncom run implementation for arm
21* @author Michael.Kang blackfin.kang@gmail.com
22* @version 78.77
23* @date 2011-11-20
24*/
25
26#include <assert.h>
27
28#include "core/arm/skyeye_common/armdefs.h"
29
30void switch_mode(arm_core_t *core, uint32_t mode)
31{
32 uint32_t tmp1, tmp2;
33 if (core->Mode == mode) {
34 //Mode not changed.
35 //printf("mode not changed\n");
36 return;
37 }
38 //printf("%d --->>> %d\n", core->Mode, mode);
39 //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);
40 if (mode != USERBANK) {
41 switch (core->Mode) {
42 case USER32MODE:
43 core->Reg_usr[0] = core->Reg[13];
44 core->Reg_usr[1] = core->Reg[14];
45 break;
46 case IRQ32MODE:
47 core->Reg_irq[0] = core->Reg[13];
48 core->Reg_irq[1] = core->Reg[14];
49 core->Spsr[IRQBANK] = core->Spsr_copy;
50 break;
51 case SVC32MODE:
52 core->Reg_svc[0] = core->Reg[13];
53 core->Reg_svc[1] = core->Reg[14];
54 core->Spsr[SVCBANK] = core->Spsr_copy;
55 break;
56 case ABORT32MODE:
57 core->Reg_abort[0] = core->Reg[13];
58 core->Reg_abort[1] = core->Reg[14];
59 core->Spsr[ABORTBANK] = core->Spsr_copy;
60 break;
61 case UNDEF32MODE:
62 core->Reg_undef[0] = core->Reg[13];
63 core->Reg_undef[1] = core->Reg[14];
64 core->Spsr[UNDEFBANK] = core->Spsr_copy;
65 break;
66 case FIQ32MODE:
67 core->Reg_firq[0] = core->Reg[13];
68 core->Reg_firq[1] = core->Reg[14];
69 core->Spsr[FIQBANK] = core->Spsr_copy;
70 break;
71
72 }
73
74 switch (mode) {
75 case USER32MODE:
76 core->Reg[13] = core->Reg_usr[0];
77 core->Reg[14] = core->Reg_usr[1];
78 core->Bank = USERBANK;
79 break;
80 case IRQ32MODE:
81 core->Reg[13] = core->Reg_irq[0];
82 core->Reg[14] = core->Reg_irq[1];
83 core->Spsr_copy = core->Spsr[IRQBANK];
84 core->Bank = IRQBANK;
85 break;
86 case SVC32MODE:
87 core->Reg[13] = core->Reg_svc[0];
88 core->Reg[14] = core->Reg_svc[1];
89 core->Spsr_copy = core->Spsr[SVCBANK];
90 core->Bank = SVCBANK;
91 break;
92 case ABORT32MODE:
93 core->Reg[13] = core->Reg_abort[0];
94 core->Reg[14] = core->Reg_abort[1];
95 core->Spsr_copy = core->Spsr[ABORTBANK];
96 core->Bank = ABORTBANK;
97 break;
98 case UNDEF32MODE:
99 core->Reg[13] = core->Reg_undef[0];
100 core->Reg[14] = core->Reg_undef[1];
101 core->Spsr_copy = core->Spsr[UNDEFBANK];
102 core->Bank = UNDEFBANK;
103 break;
104 case FIQ32MODE:
105 core->Reg[13] = core->Reg_firq[0];
106 core->Reg[14] = core->Reg_firq[1];
107 core->Spsr_copy = core->Spsr[FIQBANK];
108 core->Bank = FIQBANK;
109 break;
110
111 }
112 core->Mode = mode;
113 //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);
114 //printf("\n--------------------------------------\n");
115 }
116 else {
117 printf("user mode\n");
118 exit(-2);
119 }
120}
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 @@
1/* Copyright (C)
2* 2011 - Michael.Kang blackfin.kang@gmail.com
3* This program is free software; you can redistribute it and/or
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18
19#ifndef __ARM_DYNCOM_RUN__
20#define __ARM_DYNCOM_RUN__
21
22#include "core/arm/skyeye_common/skyeye_types.h"
23
24void switch_mode(arm_core_t *core, uint32_t mode);
25
26/* FIXME, we temporarily think thumb instruction is always 16 bit */
27static inline uint32 GET_INST_SIZE(arm_core_t* core){
28 return core->TFlag? 2 : 4;
29}
30
31/**
32* @brief Read R15 and forced R15 to wold align, used address calculation
33*
34* @param core
35* @param Rn
36*
37* @return
38*/
39static inline addr_t CHECK_READ_REG15_WA(arm_core_t* core, int Rn){
40 return (Rn == 15)? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
41}
42
43/**
44* @brief Read R15, used to data processing with pc
45*
46* @param core
47* @param Rn
48*
49* @return
50*/
51static inline uint32 CHECK_READ_REG15(arm_core_t* core, int Rn){
52 return (Rn == 15)? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
53}
54
55#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 @@
1/* Copyright (C)
2* 2011 - Michael.Kang blackfin.kang@gmail.com
3* This program is free software; you can redistribute it and/or
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18/**
19* @file arm_dyncom_thumb.c
20* @brief The thumb dynamic interpreter
21* @author Michael.Kang blackfin.kang@gmail.com
22* @version 78.77
23* @date 2011-11-07
24*/
25
26/* We can provide simple Thumb simulation by decoding the Thumb
27instruction into its corresponding ARM instruction, and using the
28existing ARM simulator. */
29
30#include "core/arm/skyeye_common/skyeye_defs.h"
31
32#ifndef MODET /* required for the Thumb instruction support */
33#if 1
34#error "MODET needs to be defined for the Thumb world to work"
35#else
36#define MODET (1)
37#endif
38#endif
39
40#include "core/arm/skyeye_common/armos.h"
41#include "core/arm/dyncom/arm_dyncom_thumb.h"
42
43/* Decode a 16bit Thumb instruction. The instruction is in the low
44 16-bits of the tinstr field, with the following Thumb instruction
45 held in the high 16-bits. Passing in two Thumb instructions allows
46 easier simulation of the special dual BL instruction. */
47
48tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size)
49{
50 tdstate valid = t_uninitialized;
51 ARMword next_instr;
52 ARMword tinstr;
53 tinstr = instr;
54 /* The endian should be judge here */
55 #if 0
56 if (state->bigendSig) {
57 next_instr = tinstr & 0xFFFF;
58 tinstr >>= 16;
59 }
60 else {
61 next_instr = tinstr >> 16;
62 tinstr &= 0xFFFF;
63 }
64 #endif
65 if((addr & 0x3) != 0)
66 tinstr = instr >> 16;
67 else
68 tinstr &= 0xFFFF;
69
70 //printf("In %s, instr=0x%x, tinstr=0x%x, r15=0x%x\n", __FUNCTION__, instr, tinstr, cpu->translate_pc);
71#if 1 /* debugging to catch non updates */
72 *ainstr = 0xDEADC0DE;
73#endif
74
75 switch ((tinstr & 0xF800) >> 11) {
76 case 0: /* LSL */
77 case 1: /* LSR */
78 case 2: /* ASR */
79 /* Format 1 */
80 *ainstr = 0xE1B00000 /* base opcode */
81 | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */
82 |((tinstr & 0x07C0) << (7 - 6)) /* imm5 */
83 |((tinstr & 0x0038) >> 3) /* Rs */
84 |((tinstr & 0x0007) << 12); /* Rd */
85 break;
86 case 3: /* ADD/SUB */
87 /* Format 2 */
88 {
89 ARMword subset[4] = {
90 0xE0900000, /* ADDS Rd,Rs,Rn */
91 0xE0500000, /* SUBS Rd,Rs,Rn */
92 0xE2900000, /* ADDS Rd,Rs,#imm3 */
93 0xE2500000 /* SUBS Rd,Rs,#imm3 */
94 };
95 /* It is quicker indexing into a table, than performing switch
96 or conditionals: */
97 *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */
98 |((tinstr & 0x01C0) >> 6) /* Rn or imm3 */
99 |((tinstr & 0x0038) << (16 - 3)) /* Rs */
100 |((tinstr & 0x0007) << (12 - 0)); /* Rd */
101 }
102 break;
103 case 4: /* MOV */
104 case 5: /* CMP */
105 case 6: /* ADD */
106 case 7: /* SUB */
107 /* Format 3 */
108 {
109 ARMword subset[4] = {
110 0xE3B00000, /* MOVS Rd,#imm8 */
111 0xE3500000, /* CMP Rd,#imm8 */
112 0xE2900000, /* ADDS Rd,Rd,#imm8 */
113 0xE2500000, /* SUBS Rd,Rd,#imm8 */
114 };
115 *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */
116 |((tinstr & 0x00FF) >> 0) /* imm8 */
117 |((tinstr & 0x0700) << (16 - 8)) /* Rn */
118 |((tinstr & 0x0700) << (12 - 8)); /* Rd */
119 }
120 break;
121 case 8: /* Arithmetic and high register transfers */
122 /* TODO: Since the subsets for both Format 4 and Format 5
123 instructions are made up of different ARM encodings, we could
124 save the following conditional, and just have one large
125 subset. */
126 if ((tinstr & (1 << 10)) == 0) {
127 typedef enum
128 { t_norm, t_shift, t_neg, t_mul }otype_t;
129
130 /* Format 4 */
131 struct
132 {
133 ARMword opcode;
134 otype_t otype;
135 }
136 subset[16] = {
137 {
138 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */
139 {
140 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */
141 {
142 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */
143 {
144 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */
145 {
146 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */
147 {
148 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */
149 {
150 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */
151 {
152 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */
153 {
154 0xE1100000, t_norm}, /* TST Rd,Rs */
155 {
156 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */
157 {
158 0xE1500000, t_norm}, /* CMP Rd,Rs */
159 {
160 0xE1700000, t_norm}, /* CMN Rd,Rs */
161 {
162 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */
163 {
164 0xE0100090, t_mul}, /* MULS Rd,Rd,Rs */
165 {
166 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */
167 {
168 0xE1F00000, t_norm} /* MVNS Rd,Rs */
169 };
170 *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
171 switch (subset[(tinstr & 0x03C0) >> 6].otype) {
172 case t_norm:
173 *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */
174 |((tinstr & 0x0007) << 12) /* Rd */
175 |((tinstr & 0x0038) >> 3); /* Rs */
176 break;
177 case t_shift:
178 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
179 |((tinstr & 0x0007) >> 0) /* Rm */
180 |((tinstr & 0x0038) << (8 - 3)); /* Rs */
181 break;
182 case t_neg:
183 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
184 |((tinstr & 0x0038) << (16 - 3)); /* Rn */
185 break;
186 case t_mul:
187 *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */
188 |((tinstr & 0x0007) << 8) /* Rs */
189 |((tinstr & 0x0038) >> 3); /* Rm */
190 break;
191 }
192 }
193 else {
194 /* Format 5 */
195 ARMword Rd = ((tinstr & 0x0007) >> 0);
196 ARMword Rs = ((tinstr & 0x0038) >> 3);
197 if (tinstr & (1 << 7))
198 Rd += 8;
199 if (tinstr & (1 << 6))
200 Rs += 8;
201 switch ((tinstr & 0x03C0) >> 6) {
202 case 0x1: /* ADD Rd,Rd,Hs */
203 case 0x2: /* ADD Hd,Hd,Rs */
204 case 0x3: /* ADD Hd,Hd,Hs */
205 *ainstr = 0xE0800000 /* base */
206 | (Rd << 16) /* Rn */
207 |(Rd << 12) /* Rd */
208 |(Rs << 0); /* Rm */
209 break;
210 case 0x5: /* CMP Rd,Hs */
211 case 0x6: /* CMP Hd,Rs */
212 case 0x7: /* CMP Hd,Hs */
213 *ainstr = 0xE1500000 /* base */
214 | (Rd << 16) /* Rn */
215 |(Rd << 12) /* Rd */
216 |(Rs << 0); /* Rm */
217 break;
218 case 0x9: /* MOV Rd,Hs */
219 case 0xA: /* MOV Hd,Rs */
220 case 0xB: /* MOV Hd,Hs */
221 *ainstr = 0xE1A00000 /* base */
222 | (Rd << 16) /* Rn */
223 |(Rd << 12) /* Rd */
224 |(Rs << 0); /* Rm */
225 break;
226 case 0xC: /* BX Rs */
227 case 0xD: /* BX Hs */
228 *ainstr = 0xE12FFF10 /* base */
229 | ((tinstr & 0x0078) >> 3); /* Rd */
230 break;
231 case 0x0: /* UNDEFINED */
232 case 0x4: /* UNDEFINED */
233 case 0x8: /* UNDEFINED */
234 valid = t_undefined;
235 break;
236 case 0xE: /* BLX */
237 case 0xF: /* BLX */
238
239 //if (state->is_v5) {
240 if(1){
241 //valid = t_branch;
242 #if 1
243 *ainstr = 0xE1200030 /* base */
244 |(Rs << 0); /* Rm */
245 #endif
246 } else {
247 valid = t_undefined;
248 }
249 break;
250 }
251 }
252 break;
253 case 9: /* LDR Rd,[PC,#imm8] */
254 /* Format 6 */
255 *ainstr = 0xE59F0000 /* base */
256 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
257 |((tinstr & 0x00FF) << (2 - 0)); /* off8 */
258 break;
259 case 10:
260 case 11:
261 /* TODO: Format 7 and Format 8 perform the same ARM encoding, so
262 the following could be merged into a single subset, saving on
263 the following boolean: */
264 if ((tinstr & (1 << 9)) == 0) {
265 /* Format 7 */
266 ARMword subset[4] = {
267 0xE7800000, /* STR Rd,[Rb,Ro] */
268 0xE7C00000, /* STRB Rd,[Rb,Ro] */
269 0xE7900000, /* LDR Rd,[Rb,Ro] */
270 0xE7D00000 /* LDRB Rd,[Rb,Ro] */
271 };
272 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
273 |((tinstr & 0x0007) << (12 - 0)) /* Rd */
274 |((tinstr & 0x0038) << (16 - 3)) /* Rb */
275 |((tinstr & 0x01C0) >> 6); /* Ro */
276 }
277 else {
278 /* Format 8 */
279 ARMword subset[4] = {
280 0xE18000B0, /* STRH Rd,[Rb,Ro] */
281 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */
282 0xE19000B0, /* LDRH Rd,[Rb,Ro] */
283 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */
284 };
285 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
286 |((tinstr & 0x0007) << (12 - 0)) /* Rd */
287 |((tinstr & 0x0038) << (16 - 3)) /* Rb */
288 |((tinstr & 0x01C0) >> 6); /* Ro */
289 }
290 break;
291 case 12: /* STR Rd,[Rb,#imm5] */
292 case 13: /* LDR Rd,[Rb,#imm5] */
293 case 14: /* STRB Rd,[Rb,#imm5] */
294 case 15: /* LDRB Rd,[Rb,#imm5] */
295 /* Format 9 */
296 {
297 ARMword subset[4] = {
298 0xE5800000, /* STR Rd,[Rb,#imm5] */
299 0xE5900000, /* LDR Rd,[Rb,#imm5] */
300 0xE5C00000, /* STRB Rd,[Rb,#imm5] */
301 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */
302 };
303 /* The offset range defends on whether we are transferring a
304 byte or word value: */
305 *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */
306 |((tinstr & 0x0007) << (12 - 0)) /* Rd */
307 |((tinstr & 0x0038) << (16 - 3)) /* Rb */
308 |((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */
309 }
310 break;
311 case 16: /* STRH Rd,[Rb,#imm5] */
312 case 17: /* LDRH Rd,[Rb,#imm5] */
313 /* Format 10 */
314 *ainstr = ((tinstr & (1 << 11)) /* base */
315 ? 0xE1D000B0 /* LDRH */
316 : 0xE1C000B0) /* STRH */
317 |((tinstr & 0x0007) << (12 - 0)) /* Rd */
318 |((tinstr & 0x0038) << (16 - 3)) /* Rb */
319 |((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */
320 |((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */
321 break;
322 case 18: /* STR Rd,[SP,#imm8] */
323 case 19: /* LDR Rd,[SP,#imm8] */
324 /* Format 11 */
325 *ainstr = ((tinstr & (1 << 11)) /* base */
326 ? 0xE59D0000 /* LDR */
327 : 0xE58D0000) /* STR */
328 |((tinstr & 0x0700) << (12 - 8)) /* Rd */
329 |((tinstr & 0x00FF) << 2); /* off8 */
330 break;
331 case 20: /* ADD Rd,PC,#imm8 */
332 case 21: /* ADD Rd,SP,#imm8 */
333 /* Format 12 */
334 if ((tinstr & (1 << 11)) == 0) {
335 /* NOTE: The PC value used here should by word aligned */
336 /* We encode shift-left-by-2 in the rotate immediate field,
337 so no shift of off8 is needed. */
338 *ainstr = 0xE28F0F00 /* base */
339 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
340 |(tinstr & 0x00FF); /* off8 */
341 }
342 else {
343 /* We encode shift-left-by-2 in the rotate immediate field,
344 so no shift of off8 is needed. */
345 *ainstr = 0xE28D0F00 /* base */
346 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
347 |(tinstr & 0x00FF); /* off8 */
348 }
349 break;
350 case 22:
351 case 23:
352 if ((tinstr & 0x0F00) == 0x0000) {
353 /* Format 13 */
354 /* NOTE: The instruction contains a shift left of 2
355 equivalent (implemented as ROR #30): */
356 *ainstr = ((tinstr & (1 << 7)) /* base */
357 ? 0xE24DDF00 /* SUB */
358 : 0xE28DDF00) /* ADD */
359 |(tinstr & 0x007F); /* off7 */
360 }
361 else if ((tinstr & 0x0F00) == 0x0e00)
362 *ainstr = 0xEF000000 | SWI_Breakpoint;
363 else {
364 /* Format 14 */
365 ARMword subset[4] = {
366 0xE92D0000, /* STMDB sp!,{rlist} */
367 0xE92D4000, /* STMDB sp!,{rlist,lr} */
368 0xE8BD0000, /* LDMIA sp!,{rlist} */
369 0xE8BD8000 /* LDMIA sp!,{rlist,pc} */
370 };
371 *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] /* base */
372 |(tinstr & 0x00FF); /* mask8 */
373 }
374 break;
375 case 24: /* STMIA */
376 case 25: /* LDMIA */
377 /* Format 15 */
378 *ainstr = ((tinstr & (1 << 11)) /* base */
379 ? 0xE8B00000 /* LDMIA */
380 : 0xE8A00000) /* STMIA */
381 |((tinstr & 0x0700) << (16 - 8)) /* Rb */
382 |(tinstr & 0x00FF); /* mask8 */
383 break;
384 case 26: /* Bcc */
385 case 27: /* Bcc/SWI */
386 if ((tinstr & 0x0F00) == 0x0F00) {
387 #if 0
388 if (tinstr == (ARMul_ABORTWORD & 0xffff) &&
389 state->AbortAddr == pc) {
390 *ainstr = ARMul_ABORTWORD;
391 break;
392 }
393 #endif
394 /* Format 17 : SWI */
395 *ainstr = 0xEF000000;
396 /* Breakpoint must be handled specially. */
397 if ((tinstr & 0x00FF) == 0x18)
398 *ainstr |= ((tinstr & 0x00FF) << 16);
399 /* New breakpoint value. See gdb/arm-tdep.c */
400 else if ((tinstr & 0x00FF) == 0xFE)
401 *ainstr |= SWI_Breakpoint;
402 else
403 *ainstr |= (tinstr & 0x00FF);
404 }
405 else if ((tinstr & 0x0F00) != 0x0E00) {
406 /* Format 16 */
407 #if 0
408 int doit = FALSE;
409 /* TODO: Since we are doing a switch here, we could just add
410 the SWI and undefined instruction checks into this
411 switch to same on a couple of conditionals: */
412 switch ((tinstr & 0x0F00) >> 8) {
413 case EQ:
414 doit = ZFLAG;
415 break;
416 case NE:
417 doit = !ZFLAG;
418 break;
419 case VS:
420 doit = VFLAG;
421 break;
422 case VC:
423 doit = !VFLAG;
424 break;
425 case MI:
426 doit = NFLAG;
427 break;
428 case PL:
429 doit = !NFLAG;
430 break;
431 case CS:
432 doit = CFLAG;
433 break;
434 case CC:
435 doit = !CFLAG;
436 break;
437 case HI:
438 doit = (CFLAG && !ZFLAG);
439 break;
440 case LS:
441 doit = (!CFLAG || ZFLAG);
442 break;
443 case GE:
444 doit = ((!NFLAG && !VFLAG)
445 || (NFLAG && VFLAG));
446 break;
447 case LT:
448 doit = ((NFLAG && !VFLAG)
449 || (!NFLAG && VFLAG));
450 break;
451 case GT:
452 doit = ((!NFLAG && !VFLAG && !ZFLAG)
453 || (NFLAG && VFLAG && !ZFLAG));
454 break;
455 case LE:
456 doit = ((NFLAG && !VFLAG)
457 || (!NFLAG && VFLAG)) || ZFLAG;
458 break;
459 }
460 if (doit) {
461 state->Reg[15] = (pc + 4
462 + (((tinstr & 0x7F) << 1)
463 | ((tinstr & (1 << 7)) ?
464 0xFFFFFF00 : 0)));
465 FLUSHPIPE;
466 }
467 #endif
468 valid = t_branch;
469 }
470 else /* UNDEFINED : cc=1110(AL) uses different format */
471 valid = t_undefined;
472 break;
473 case 28: /* B */
474 /* Format 18 */
475 #if 0
476 state->Reg[15] = (pc + 4 + (((tinstr & 0x3FF) << 1)
477 | ((tinstr & (1 << 10)) ?
478 0xFFFFF800 : 0)));
479 #endif
480 //FLUSHPIPE;
481 valid = t_branch;
482 break;
483 case 29:
484 if(tinstr & 0x1)
485 valid = t_undefined;
486 else{
487 /* BLX 1 for armv5t and above */
488 //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);
489 valid = t_branch;
490 }
491 break;
492 case 30: /* BL instruction 1 */
493 /* Format 19 */
494 /* There is no single ARM instruction equivalent for this Thumb
495 instruction. To keep the simulation simple (from the user
496 perspective) we check if the following instruction is the
497 second half of this BL, and if it is we simulate it
498 immediately. */
499 valid = t_branch;
500 break;
501 case 31: /* BL instruction 2 */
502 /* Format 19 */
503 /* There is no single ARM instruction equivalent for this
504 instruction. Also, it should only ever be matched with the
505 fmt19 "BL instruction 1" instruction. However, we do allow
506 the simulation of it on its own, with undefined results if
507 r14 is not suitably initialised. */
508 {
509 #if 0
510 ARMword tmp = (pc + 2);
511 state->Reg[15] =
512 (state->Reg[14] + ((tinstr & 0x07FF) << 1));
513 state->Reg[14] = (tmp | 1);
514 #endif
515 valid = t_branch;
516 }
517 break;
518 }
519 *inst_size = 2;
520 return valid;
521}
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 @@
1/* Copyright (C)
2* 2011 - Michael.Kang blackfin.kang@gmail.com
3* This program is free software; you can redistribute it and/or
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18
19/**
20* @file arm_dyncom_thumb.h
21* @brief The thumb dyncom
22* @author Michael.Kang blackfin.kang@gmail.com
23* @version 78.77
24* @date 2011-11-07
25*/
26
27#ifndef __ARM_DYNCOM_THUMB_H__
28#define __ARM_DYNCOM_THUMB_H__
29
30#include "core/arm/skyeye_common/armdefs.h"
31#include "core/arm/skyeye_common/skyeye_types.h"
32
33enum tdstate {
34 t_undefined, // Undefined Thumb instruction
35 t_decoded, // Instruction decoded to ARM equivalent
36 t_branch, // Thumb branch (already processed)
37 t_uninitialized,
38};
39
40tdstate
41thumb_translate(addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size);
42static inline uint32 get_thumb_instr(uint32 instr, addr_t pc){
43 uint32 tinstr;
44 if ((pc & 0x3) != 0)
45 tinstr = instr >> 16;
46 else
47 tinstr = instr & 0xFFFF;
48 return tinstr;
49}
50
51#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 @@
4 4
5#include "core/arm/interpreter/arm_interpreter.h" 5#include "core/arm/interpreter/arm_interpreter.h"
6 6
7const static cpu_config_t s_arm11_cpu_info = { 7const static cpu_config_t arm11_cpu_info = {
8 "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE 8 "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE
9}; 9};
10 10
@@ -17,12 +17,11 @@ ARM_Interpreter::ARM_Interpreter() {
17 ARMul_NewState(state); 17 ARMul_NewState(state);
18 18
19 state->abort_model = 0; 19 state->abort_model = 0;
20 state->cpu = (cpu_config_t*)&s_arm11_cpu_info; 20 state->cpu = (cpu_config_t*)&arm11_cpu_info;
21 state->bigendSig = LOW; 21 state->bigendSig = LOW;
22 22
23 ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); 23 ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
24 state->lateabtSig = LOW; 24 state->lateabtSig = LOW;
25 mmu_init(state);
26 25
27 // Reset the core to initial state 26 // Reset the core to initial state
28 ARMul_CoProInit(state); 27 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 @@
7#include "common/common.h" 7#include "common/common.h"
8 8
9#include "core/arm/arm_interface.h" 9#include "core/arm/arm_interface.h"
10#include "core/arm/interpreter/armdefs.h" 10#include "core/arm/skyeye_common/armdefs.h"
11#include "core/arm/interpreter/armemu.h" 11#include "core/arm/skyeye_common/armemu.h"
12 12
13class ARM_Interpreter : virtual public ARM_Interface { 13class ARM_Interpreter final : virtual public ARM_Interface {
14public: 14public:
15 15
16 ARM_Interpreter(); 16 ARM_Interpreter();
@@ -20,60 +20,60 @@ public:
20 * Set the Program Counter to an address 20 * Set the Program Counter to an address
21 * @param addr Address to set PC to 21 * @param addr Address to set PC to
22 */ 22 */
23 void SetPC(u32 pc); 23 void SetPC(u32 pc) override;
24 24
25 /* 25 /*
26 * Get the current Program Counter 26 * Get the current Program Counter
27 * @return Returns current PC 27 * @return Returns current PC
28 */ 28 */
29 u32 GetPC() const; 29 u32 GetPC() const override;
30 30
31 /** 31 /**
32 * Get an ARM register 32 * Get an ARM register
33 * @param index Register index (0-15) 33 * @param index Register index (0-15)
34 * @return Returns the value in the register 34 * @return Returns the value in the register
35 */ 35 */
36 u32 GetReg(int index) const; 36 u32 GetReg(int index) const override;
37 37
38 /** 38 /**
39 * Set an ARM register 39 * Set an ARM register
40 * @param index Register index (0-15) 40 * @param index Register index (0-15)
41 * @param value Value to set register to 41 * @param value Value to set register to
42 */ 42 */
43 void SetReg(int index, u32 value); 43 void SetReg(int index, u32 value) override;
44 44
45 /** 45 /**
46 * Get the current CPSR register 46 * Get the current CPSR register
47 * @return Returns the value of the CPSR register 47 * @return Returns the value of the CPSR register
48 */ 48 */
49 u32 GetCPSR() const; 49 u32 GetCPSR() const override;
50 50
51 /** 51 /**
52 * Set the current CPSR register 52 * Set the current CPSR register
53 * @param cpsr Value to set CPSR to 53 * @param cpsr Value to set CPSR to
54 */ 54 */
55 void SetCPSR(u32 cpsr); 55 void SetCPSR(u32 cpsr) override;
56 56
57 /** 57 /**
58 * Returns the number of clock ticks since the last reset 58 * Returns the number of clock ticks since the last reset
59 * @return Returns number of clock ticks 59 * @return Returns number of clock ticks
60 */ 60 */
61 u64 GetTicks() const; 61 u64 GetTicks() const override;
62 62
63 /** 63 /**
64 * Saves the current CPU context 64 * Saves the current CPU context
65 * @param ctx Thread context to save 65 * @param ctx Thread context to save
66 */ 66 */
67 void SaveContext(ThreadContext& ctx); 67 void SaveContext(ThreadContext& ctx) override;
68 68
69 /** 69 /**
70 * Loads a CPU context 70 * Loads a CPU context
71 * @param ctx Thread context to load 71 * @param ctx Thread context to load
72 */ 72 */
73 void LoadContext(const ThreadContext& ctx); 73 void LoadContext(const ThreadContext& ctx) override;
74 74
75 /// Prepare core for thread reschedule (if needed to correctly handle state) 75 /// Prepare core for thread reschedule (if needed to correctly handle state)
76 void PrepareReschedule(); 76 void PrepareReschedule() override;
77 77
78protected: 78protected:
79 79
@@ -81,7 +81,7 @@ protected:
81 * Executes the given number of instructions 81 * Executes the given number of instructions
82 * @param num_instructions Number of instructions to executes 82 * @param num_instructions Number of instructions to executes
83 */ 83 */
84 void ExecuteInstructions(int num_instructions); 84 void ExecuteInstructions(int num_instructions) override;
85 85
86private: 86private:
87 87
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 @@
15 along with this program; if not, write to the Free Software 15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17 17
18 18#include "core/arm/skyeye_common/armdefs.h"
19#include "core/arm/interpreter/armdefs.h" 19#include "core/arm/skyeye_common/armemu.h"
20#include "core/arm/interpreter/armos.h" 20#include "core/arm/skyeye_common/vfp/vfp.h"
21#include "core/arm/interpreter/armemu.h"
22#include "core/arm/interpreter/vfp/vfp.h"
23 21
24//chy 2005-07-08 22//chy 2005-07-08
25//#include "ansidecl.h" 23//#include "ansidecl.h"
26//chy ------- 24//chy -------
27//#include "iwmmxt.h" 25//#include "iwmmxt.h"
28 26
29
30//chy 2005-09-19 add CP6 MRC support (for get irq number and base)
31extern unsigned xscale_cp6_mrc (ARMul_State * state, unsigned type,
32 ARMword instr, ARMword * data);
33//chy 2005-09-19---------------
34
35extern unsigned xscale_cp13_init (ARMul_State * state);
36extern unsigned xscale_cp13_exit (ARMul_State * state);
37extern unsigned xscale_cp13_ldc (ARMul_State * state, unsigned type,
38 ARMword instr, ARMword data);
39extern unsigned xscale_cp13_stc (ARMul_State * state, unsigned type,
40 ARMword instr, ARMword * data);
41extern unsigned xscale_cp13_mrc (ARMul_State * state, unsigned type,
42 ARMword instr, ARMword * data);
43extern unsigned xscale_cp13_mcr (ARMul_State * state, unsigned type,
44 ARMword instr, ARMword data);
45extern unsigned xscale_cp13_cdp (ARMul_State * state, unsigned type,
46 ARMword instr);
47extern unsigned xscale_cp13_read_reg (ARMul_State * state, unsigned reg,
48 ARMword * data);
49extern unsigned xscale_cp13_write_reg (ARMul_State * state, unsigned reg,
50 ARMword data);
51extern unsigned xscale_cp14_init (ARMul_State * state);
52extern unsigned xscale_cp14_exit (ARMul_State * state);
53extern unsigned xscale_cp14_ldc (ARMul_State * state, unsigned type,
54 ARMword instr, ARMword data);
55extern unsigned xscale_cp14_stc (ARMul_State * state, unsigned type,
56 ARMword instr, ARMword * data);
57extern unsigned xscale_cp14_mrc (ARMul_State * state, unsigned type,
58 ARMword instr, ARMword * data);
59extern unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type,
60 ARMword instr, ARMword data);
61extern unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type,
62 ARMword instr);
63extern unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg,
64 ARMword * data);
65extern unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg,
66 ARMword data);
67extern unsigned xscale_cp15_init (ARMul_State * state);
68extern unsigned xscale_cp15_exit (ARMul_State * state);
69extern unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type,
70 ARMword instr, ARMword data);
71extern unsigned xscale_cp15_stc (ARMul_State * state, unsigned type,
72 ARMword instr, ARMword * data);
73extern unsigned xscale_cp15_mrc (ARMul_State * state, unsigned type,
74 ARMword instr, ARMword * data);
75extern unsigned xscale_cp15_mcr (ARMul_State * state, unsigned type,
76 ARMword instr, ARMword data);
77extern unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type,
78 ARMword instr);
79extern unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg,
80 ARMword * data);
81extern unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg,
82 ARMword data);
83extern unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
84 unsigned cpnum);
85
86/* Dummy Co-processors. */ 27/* Dummy Co-processors. */
87 28
88static unsigned 29static unsigned
89NoCoPro3R (ARMul_State * state, 30NoCoPro3R(ARMul_State * state,
90 unsigned a, ARMword b) 31unsigned a, ARMword b)
91{ 32{
92 return ARMul_CANT; 33 return ARMul_CANT;
93} 34}
94 35
95static unsigned 36static unsigned
96NoCoPro4R (ARMul_State * state, 37NoCoPro4R(ARMul_State * state,
97 unsigned a, 38unsigned a,
98 ARMword b, ARMword c) 39ARMword b, ARMword c)
99{ 40{
100 return ARMul_CANT; 41 return ARMul_CANT;
101} 42}
102 43
103static unsigned 44static unsigned
104NoCoPro4W (ARMul_State * state, 45NoCoPro4W(ARMul_State * state,
105 unsigned a, 46unsigned a,
106 ARMword b, ARMword * c) 47ARMword b, ARMword * c)
107{ 48{
108 return ARMul_CANT; 49 return ARMul_CANT;
109} 50}
110 51
111static unsigned 52static unsigned
112NoCoPro5R (ARMul_State * state, 53NoCoPro5R(ARMul_State * state,
113 unsigned a, 54unsigned a,
114 ARMword b, 55ARMword b,
115 ARMword c, ARMword d) 56ARMword c, ARMword d)
116{ 57{
117 return ARMul_CANT; 58 return ARMul_CANT;
118} 59}
119 60
120static unsigned 61static unsigned
121NoCoPro5W (ARMul_State * state, 62NoCoPro5W(ARMul_State * state,
122 unsigned a, 63unsigned a,
123 ARMword b, 64ARMword b,
124 ARMword * c, ARMword * d ) 65ARMword * c, ARMword * d)
125{ 66{
126 return ARMul_CANT; 67 return ARMul_CANT;
127} 68}
128 69
129/* The XScale Co-processors. */ 70/* The XScale Co-processors. */
130 71
131/* Coprocessor 15: System Control. */ 72/* Coprocessor 15: System Control. */
132static void write_cp14_reg (unsigned, ARMword); 73static void write_cp14_reg(unsigned, ARMword);
133static ARMword read_cp14_reg (unsigned); 74static ARMword read_cp14_reg(unsigned);
134
135/* There are two sets of registers for copro 15.
136 One set is available when opcode_2 is 0 and
137 the other set when opcode_2 >= 1. */
138static ARMword XScale_cp15_opcode_2_is_0_Regs[16];
139static ARMword XScale_cp15_opcode_2_is_not_0_Regs[16];
140/* There are also a set of breakpoint registers
141 which are accessed via CRm instead of opcode_2. */
142static ARMword XScale_cp15_DBR1;
143static ARMword XScale_cp15_DBCON;
144static ARMword XScale_cp15_IBCR0;
145static ARMword XScale_cp15_IBCR1;
146
147static unsigned
148XScale_cp15_init (ARMul_State * state)
149{
150 int i;
151
152 for (i = 16; i--;) {
153 XScale_cp15_opcode_2_is_0_Regs[i] = 0;
154 XScale_cp15_opcode_2_is_not_0_Regs[i] = 0;
155 }
156
157 /* Initialise the processor ID. */
158 //chy 2003-03-24, is same as cpu id in skyeye_options.c
159 //XScale_cp15_opcode_2_is_0_Regs[0] = 0x69052000;
160 XScale_cp15_opcode_2_is_0_Regs[0] = 0x69050000;
161
162 /* Initialise the cache type. */
163 XScale_cp15_opcode_2_is_not_0_Regs[0] = 0x0B1AA1AA;
164
165 /* Initialise the ARM Control Register. */
166 XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078;
167
168 return No_exp;
169}
170
171/* Check an access to a register. */
172
173static unsigned
174check_cp15_access (ARMul_State * state,
175 unsigned reg,
176 unsigned CRm, unsigned opcode_1, unsigned opcode_2)
177{
178 /* Do not allow access to these register in USER mode. */
179 //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
180 if (state->Mode == USER26MODE || state->Mode == USER32MODE )
181 return ARMul_CANT;
182
183 /* Opcode_1should be zero. */
184 if (opcode_1 != 0)
185 return ARMul_CANT;
186
187 /* Different register have different access requirements. */
188 switch (reg) {
189 case 0:
190 case 1:
191 /* CRm must be 0. Opcode_2 can be anything. */
192 if (CRm != 0)
193 return ARMul_CANT;
194 break;
195 case 2:
196 case 3:
197 /* CRm must be 0. Opcode_2 must be zero. */
198 if ((CRm != 0) || (opcode_2 != 0))
199 return ARMul_CANT;
200 break;
201 case 4:
202 /* Access not allowed. */
203 return ARMul_CANT;
204 case 5:
205 case 6:
206 /* Opcode_2 must be zero. CRm must be 0. */
207 if ((CRm != 0) || (opcode_2 != 0))
208 return ARMul_CANT;
209 break;
210 case 7:
211 /* Permissable combinations:
212 Opcode_2 CRm
213 0 5
214 0 6
215 0 7
216 1 5
217 1 6
218 1 10
219 4 10
220 5 2
221 6 5 */
222 switch (opcode_2) {
223 default:
224 return ARMul_CANT;
225 case 6:
226 if (CRm != 5)
227 return ARMul_CANT;
228 break;
229 case 5:
230 if (CRm != 2)
231 return ARMul_CANT;
232 break;
233 case 4:
234 if (CRm != 10)
235 return ARMul_CANT;
236 break;
237 case 1:
238 if ((CRm != 5) && (CRm != 6) && (CRm != 10))
239 return ARMul_CANT;
240 break;
241 case 0:
242 if ((CRm < 5) || (CRm > 7))
243 return ARMul_CANT;
244 break;
245 }
246 break;
247
248 case 8:
249 /* Permissable combinations:
250 Opcode_2 CRm
251 0 5
252 0 6
253 0 7
254 1 5
255 1 6 */
256 if (opcode_2 > 1)
257 return ARMul_CANT;
258 if ((CRm < 5) || (CRm > 7))
259 return ARMul_CANT;
260 if (opcode_2 == 1 && CRm == 7)
261 return ARMul_CANT;
262 break;
263 case 9:
264 /* Opcode_2 must be zero or one. CRm must be 1 or 2. */
265 if (((CRm != 0) && (CRm != 1))
266 || ((opcode_2 != 1) && (opcode_2 != 2)))
267 return ARMul_CANT;
268 break;
269 case 10:
270 /* Opcode_2 must be zero or one. CRm must be 4 or 8. */
271 if (((CRm != 0) && (CRm != 1))
272 || ((opcode_2 != 4) && (opcode_2 != 8)))
273 return ARMul_CANT;
274 break;
275 case 11:
276 /* Access not allowed. */
277 return ARMul_CANT;
278 case 12:
279 /* Access not allowed. */
280 return ARMul_CANT;
281 case 13:
282 /* Opcode_2 must be zero. CRm must be 0. */
283 if ((CRm != 0) || (opcode_2 != 0))
284 return ARMul_CANT;
285 break;
286 case 14:
287 /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */
288 if (opcode_2 != 0)
289 return ARMul_CANT;
290
291 if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8)
292 && (CRm != 9))
293 return ARMul_CANT;
294 break;
295 case 15:
296 /* Opcode_2 must be zero. CRm must be 1. */
297 if ((CRm != 1) || (opcode_2 != 0))
298 return ARMul_CANT;
299 break;
300 default:
301 /* Should never happen. */
302 return ARMul_CANT;
303 }
304
305 return ARMul_DONE;
306}
307
308/* Coprocessor 13: Interrupt Controller and Bus Controller. */
309
310/* There are two sets of registers for copro 13.
311 One set (of three registers) is available when CRm is 0
312 and the other set (of six registers) when CRm is 1. */
313
314static ARMword XScale_cp13_CR0_Regs[16];
315static ARMword XScale_cp13_CR1_Regs[16];
316
317static unsigned
318XScale_cp13_init (ARMul_State * state)
319{
320 int i;
321
322 for (i = 16; i--;) {
323 XScale_cp13_CR0_Regs[i] = 0;
324 XScale_cp13_CR1_Regs[i] = 0;
325 }
326
327 return No_exp;
328}
329
330/* Check an access to a register. */
331
332static unsigned
333check_cp13_access (ARMul_State * state,
334 unsigned reg,
335 unsigned CRm, unsigned opcode_1, unsigned opcode_2)
336{
337 /* Do not allow access to these registers in USER mode. */
338 //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
339 if (state->Mode == USER26MODE || state->Mode == USER32MODE )
340 return ARMul_CANT;
341
342 /* The opcodes should be zero. */
343 if ((opcode_1 != 0) || (opcode_2 != 0))
344 return ARMul_CANT;
345
346 /* Do not allow access to these register if bit
347 13 of coprocessor 15's register 15 is zero. */
348 if (!CP_ACCESS_ALLOWED (state, 13))
349 return ARMul_CANT;
350
351 /* Registers 0, 4 and 8 are defined when CRm == 0.
352 Registers 0, 1, 4, 5, 6, 7, 8 are defined when CRm == 1.
353 For all other CRm values undefined behaviour results. */
354 if (CRm == 0) {
355 if (reg == 0 || reg == 4 || reg == 8)
356 return ARMul_DONE;
357 }
358 else if (CRm == 1) {
359 if (reg == 0 || reg == 1 || (reg >= 4 && reg <= 8))
360 return ARMul_DONE;
361 }
362
363 return ARMul_CANT;
364}
365
366/* Coprocessor 14: Performance Monitoring, Clock and Power management,
367 Software Debug. */
368
369static ARMword XScale_cp14_Regs[16];
370
371static unsigned
372XScale_cp14_init (ARMul_State * state)
373{
374 int i;
375
376 for (i = 16; i--;)
377 XScale_cp14_Regs[i] = 0;
378
379 return No_exp;
380}
381 75
382/* Check an access to a register. */ 76/* Check an access to a register. */
383 77
384static unsigned 78static unsigned
385check_cp14_access (ARMul_State * state, 79check_cp15_access(ARMul_State * state,
386 unsigned reg, 80unsigned reg,
387 unsigned CRm, unsigned opcode1, unsigned opcode2) 81unsigned CRm, unsigned opcode_1, unsigned opcode_2)
388{
389 /* Not allowed to access these register in USER mode. */
390 //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
391 if (state->Mode == USER26MODE || state->Mode == USER32MODE )
392 return ARMul_CANT;
393
394 /* CRm should be zero. */
395 if (CRm != 0)
396 return ARMul_CANT;
397
398 /* OPcodes should be zero. */
399 if (opcode1 != 0 || opcode2 != 0)
400 return ARMul_CANT;
401
402 /* Accessing registers 4 or 5 has unpredicatable results. */
403 if (reg >= 4 && reg <= 5)
404 return ARMul_CANT;
405
406 return ARMul_DONE;
407}
408
409/* Here's ARMulator's MMU definition. A few things to note:
410 1) It has eight registers, but only two are defined.
411 2) You can only access its registers with MCR and MRC.
412 3) MMU Register 0 (ID) returns 0x41440110
413 4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4
414 controls 32/26 bit program space, bit 5 controls 32/26 bit data space,
415 bit 6 controls late abort timimg and bit 7 controls big/little endian. */
416
417static ARMword MMUReg[8];
418
419static unsigned
420MMUInit (ARMul_State * state)
421{
422/* 2004-05-09 chy
423-------------------------------------------------------------
424read ARM Architecture Reference Manual
4252.6.5 Data Abort
426There are three Abort Model in ARM arch.
427
428Early Abort Model: used in some ARMv3 and earlier implementations. In this
429model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and
430the base register was unchanged for all other instructions. (oldest)
431
432Base Restored Abort Model: If a Data Abort occurs in an instruction which
433specifies base register writeback, the value in the base register is
434unchanged. (strongarm, xscale)
435
436Base Updated Abort Model: If a Data Abort occurs in an instruction which
437specifies base register writeback, the base register writeback still occurs.
438(arm720T)
439
440read PART B
441chap2 The System Control Coprocessor CP15
4422.4 Register1:control register
443L(bit 6): in some ARMv3 and earlier implementations, the abort model of the
444processor could be configured:
4450=early Abort Model Selected(now obsolete)
4461=Late Abort Model selceted(same as Base Updated Abort Model)
447
448on later processors, this bit reads as 1 and ignores writes.
449-------------------------------------------------------------
450So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
451 if lateabtSig=0, then it means Base Restored Abort Model
452because the ARMs which skyeye simulates are all belonged to ARMv4,
453so I think MMUReg[1]'s bit 6 should always be 1
454
455*/
456
457 MMUReg[1] = state->prog32Sig << 4 |
458 state->data32Sig << 5 | 1 << 6 | state->bigendSig << 7;
459 //state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7;
460
461
462 NOTICE_LOG(ARM11, "ARMul_ConsolePrint: MMU present");
463
464 return TRUE;
465}
466
467static unsigned
468MMUMRC (ARMul_State * state, unsigned type,
469 ARMword instr, ARMword * value)
470{
471 mmu_mrc (state, instr, value);
472 return (ARMul_DONE);
473}
474
475static unsigned
476MMUMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
477{
478 mmu_mcr (state, instr, value);
479 return (ARMul_DONE);
480}
481
482/* What follows is the Validation Suite Coprocessor. It uses two
483 co-processor numbers (4 and 5) and has the follwing functionality.
484 Sixteen registers. Both co-processor nuimbers can be used in an MCR
485 and MRC to access these registers. CP 4 can LDC and STC to and from
486 the registers. CP 4 and CP 5 CDP 0 will busy wait for the number of
487 cycles specified by a CP register. CP 5 CDP 1 issues a FIQ after a
488 number of cycles (specified in a CP register), CDP 2 issues an IRQW
489 in the same way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5
490 stores a 32 bit time value in a CP register (actually it's the total
491 number of N, S, I, C and F cyles). */
492
493static ARMword ValReg[16];
494
495static unsigned
496ValLDC (ARMul_State * state,
497 unsigned type, ARMword instr, ARMword data)
498{
499 static unsigned words;
500
501 if (type != ARMul_DATA)
502 words = 0;
503 else {
504 ValReg[BITS (12, 15)] = data;
505
506 if (BIT (22))
507 /* It's a long access, get two words. */
508 if (words++ != 4)
509 return ARMul_INC;
510 }
511
512 return ARMul_DONE;
513}
514
515static unsigned
516ValSTC (ARMul_State * state,
517 unsigned type, ARMword instr, ARMword * data)
518{
519 static unsigned words;
520
521 if (type != ARMul_DATA)
522 words = 0;
523 else {
524 *data = ValReg[BITS (12, 15)];
525
526 if (BIT (22))
527 /* It's a long access, get two words. */
528 if (words++ != 4)
529 return ARMul_INC;
530 }
531
532 return ARMul_DONE;
533}
534
535static unsigned
536ValMRC (ARMul_State * state,
537 unsigned type, ARMword instr, ARMword * value)
538{
539 *value = ValReg[BITS (16, 19)];
540
541 return ARMul_DONE;
542}
543
544static unsigned
545ValMCR (ARMul_State * state,
546 unsigned type, ARMword instr, ARMword value)
547{
548 ValReg[BITS (16, 19)] = value;
549
550 return ARMul_DONE;
551}
552
553static unsigned
554ValCDP (ARMul_State * state, unsigned type, ARMword instr)
555{
556 static unsigned int finish = 0;
557
558 if (BITS (20, 23) != 0)
559 return ARMul_CANT;
560
561 if (type == ARMul_FIRST) {
562 ARMword howlong;
563
564 howlong = ValReg[BITS (0, 3)];
565
566 /* First cycle of a busy wait. */
567 finish = ARMul_Time (state) + howlong;
568
569 return howlong == 0 ? ARMul_DONE : ARMul_BUSY;
570 }
571 else if (type == ARMul_BUSY) {
572 if (ARMul_Time (state) >= finish)
573 return ARMul_DONE;
574 else
575 return ARMul_BUSY;
576 }
577
578 return ARMul_CANT;
579}
580
581static unsigned
582DoAFIQ (ARMul_State * state)
583{
584 state->NfiqSig = LOW;
585 return 0;
586}
587
588static unsigned
589DoAIRQ (ARMul_State * state)
590{
591 state->NirqSig = LOW;
592 return 0;
593}
594
595static unsigned
596IntCDP (ARMul_State * state, unsigned type, ARMword instr)
597{ 82{
598 static unsigned int finish; 83 /* Do not allow access to these register in USER mode. */
599 ARMword howlong; 84 //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
600 85 if (state->Mode == USER26MODE || state->Mode == USER32MODE)
601 howlong = ValReg[BITS (0, 3)]; 86 return ARMul_CANT;
602 87
603 switch ((int) BITS (20, 23)) { 88 /* Opcode_1should be zero. */
604 case 0: 89 if (opcode_1 != 0)
605 if (type == ARMul_FIRST) { 90 return ARMul_CANT;
606 /* First cycle of a busy wait. */ 91
607 finish = ARMul_Time (state) + howlong; 92 /* Different register have different access requirements. */
608 93 switch (reg) {
609 return howlong == 0 ? ARMul_DONE : ARMul_BUSY; 94 case 0:
610 } 95 case 1:
611 else if (type == ARMul_BUSY) { 96 /* CRm must be 0. Opcode_2 can be anything. */
612 if (ARMul_Time (state) >= finish) 97 if (CRm != 0)
613 return ARMul_DONE; 98 return ARMul_CANT;
614 else 99 break;
615 return ARMul_BUSY; 100 case 2:
616 } 101 case 3:
617 return ARMul_DONE; 102 /* CRm must be 0. Opcode_2 must be zero. */
618 103 if ((CRm != 0) || (opcode_2 != 0))
619 case 1: 104 return ARMul_CANT;
620 if (howlong == 0) 105 break;
621 ARMul_Abort (state, ARMul_FIQV); 106 case 4:
622 else 107 /* Access not allowed. */
623 ARMul_ScheduleEvent (state, howlong, DoAFIQ); 108 return ARMul_CANT;
624 return ARMul_DONE; 109 case 5:
625 110 case 6:
626 case 2: 111 /* Opcode_2 must be zero. CRm must be 0. */
627 if (howlong == 0) 112 if ((CRm != 0) || (opcode_2 != 0))
628 ARMul_Abort (state, ARMul_IRQV); 113 return ARMul_CANT;
629 else 114 break;
630 ARMul_ScheduleEvent (state, howlong, DoAIRQ); 115 case 7:
631 return ARMul_DONE; 116 /* Permissable combinations:
632 117 Opcode_2 CRm
633 case 3: 118 0 5
634 state->NfiqSig = HIGH; 119 0 6
635 return ARMul_DONE; 120 0 7
636 121 1 5
637 case 4: 122 1 6
638 state->NirqSig = HIGH; 123 1 10
639 return ARMul_DONE; 124 4 10
640 125 5 2
641 case 5: 126 6 5 */
642 ValReg[BITS (0, 3)] = ARMul_Time (state); 127 switch (opcode_2) {
643 return ARMul_DONE; 128 default:
644 } 129 return ARMul_CANT;
645 130 case 6:
646 return ARMul_CANT; 131 if (CRm != 5)
132 return ARMul_CANT;
133 break;
134 case 5:
135 if (CRm != 2)
136 return ARMul_CANT;
137 break;
138 case 4:
139 if (CRm != 10)
140 return ARMul_CANT;
141 break;
142 case 1:
143 if ((CRm != 5) && (CRm != 6) && (CRm != 10))
144 return ARMul_CANT;
145 break;
146 case 0:
147 if ((CRm < 5) || (CRm > 7))
148 return ARMul_CANT;
149 break;
150 }
151 break;
152
153 case 8:
154 /* Permissable combinations:
155 Opcode_2 CRm
156 0 5
157 0 6
158 0 7
159 1 5
160 1 6 */
161 if (opcode_2 > 1)
162 return ARMul_CANT;
163 if ((CRm < 5) || (CRm > 7))
164 return ARMul_CANT;
165 if (opcode_2 == 1 && CRm == 7)
166 return ARMul_CANT;
167 break;
168 case 9:
169 /* Opcode_2 must be zero or one. CRm must be 1 or 2. */
170 if (((CRm != 0) && (CRm != 1))
171 || ((opcode_2 != 1) && (opcode_2 != 2)))
172 return ARMul_CANT;
173 break;
174 case 10:
175 /* Opcode_2 must be zero or one. CRm must be 4 or 8. */
176 if (((CRm != 0) && (CRm != 1))
177 || ((opcode_2 != 4) && (opcode_2 != 8)))
178 return ARMul_CANT;
179 break;
180 case 11:
181 /* Access not allowed. */
182 return ARMul_CANT;
183 case 12:
184 /* Access not allowed. */
185 return ARMul_CANT;
186 case 13:
187 /* Opcode_2 must be zero. CRm must be 0. */
188 if ((CRm != 0) || (opcode_2 != 0))
189 return ARMul_CANT;
190 break;
191 case 14:
192 /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */
193 if (opcode_2 != 0)
194 return ARMul_CANT;
195
196 if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8)
197 && (CRm != 9))
198 return ARMul_CANT;
199 break;
200 case 15:
201 /* Opcode_2 must be zero. CRm must be 1. */
202 if ((CRm != 1) || (opcode_2 != 0))
203 return ARMul_CANT;
204 break;
205 default:
206 /* Should never happen. */
207 return ARMul_CANT;
208 }
209
210 return ARMul_DONE;
647} 211}
648 212
649/* Install co-processor instruction handlers in this routine. */ 213/* Install co-processor instruction handlers in this routine. */
650 214
651unsigned 215unsigned
652ARMul_CoProInit (ARMul_State * state) 216ARMul_CoProInit(ARMul_State * state)
653{ 217{
654 unsigned int i; 218 unsigned int i;
655 219
656 /* Initialise tham all first. */ 220 /* Initialise tham all first. */
657 for (i = 0; i < 16; i++) 221 for (i = 0; i < 16; i++)
658 ARMul_CoProDetach (state, i); 222 ARMul_CoProDetach(state, i);
659 223
660 /* Install CoPro Instruction handlers here. 224 /* Install CoPro Instruction handlers here.
661 The format is: 225 The format is:
662 ARMul_CoProAttach (state, CP Number, Init routine, Exit routine 226 ARMul_CoProAttach (state, CP Number, Init routine, Exit routine
663 LDC routine, STC routine, MRC routine, MCR routine, 227 LDC routine, STC routine, MRC routine, MCR routine,
664 CDP routine, Read Reg routine, Write Reg routine). */ 228 CDP routine, Read Reg routine, Write Reg routine). */
665 if (state->is_ep9312) { 229 if (state->is_v6) {
666 ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4, 230 ARMul_CoProAttach(state, 10, VFPInit, NULL, VFPLDC, VFPSTC,
667 DSPMRC4, DSPMCR4, NULL, NULL, DSPCDP4, NULL, NULL); 231 VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
668 ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5, 232 ARMul_CoProAttach(state, 11, VFPInit, NULL, VFPLDC, VFPSTC,
669 DSPMRC5, DSPMCR5, NULL, NULL, DSPCDP5, NULL, NULL); 233 VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
670 ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL, 234
671 DSPMRC6, DSPMCR6, NULL, NULL, DSPCDP6, NULL, NULL); 235 /*ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
672 } 236 MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);*/
673 else { 237 }
674 ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC, 238 //chy 2003-09-03 do it in future!!!!????
675 ValMRC, ValMCR, NULL, NULL, ValCDP, NULL, NULL);
676
677 ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL,
678 ValMRC, ValMCR, NULL, NULL, IntCDP, NULL, NULL);
679 }
680
681 if (state->is_XScale) {
682 //chy 2005-09-19, for PXA27x's CP6
683 if (state->is_pxa27x) {
684 ARMul_CoProAttach (state, 6, NULL, NULL,
685 NULL, NULL, xscale_cp6_mrc,
686 NULL, NULL, NULL, NULL, NULL, NULL);
687 }
688 //chy 2005-09-19 end-------------
689 ARMul_CoProAttach (state, 13, xscale_cp13_init,
690 xscale_cp13_exit, xscale_cp13_ldc,
691 xscale_cp13_stc, xscale_cp13_mrc,
692 xscale_cp13_mcr, NULL, NULL, xscale_cp13_cdp,
693 xscale_cp13_read_reg,
694 xscale_cp13_write_reg);
695
696 ARMul_CoProAttach (state, 14, xscale_cp14_init,
697 xscale_cp14_exit, xscale_cp14_ldc,
698 xscale_cp14_stc, xscale_cp14_mrc,
699 xscale_cp14_mcr, NULL, NULL, xscale_cp14_cdp,
700 xscale_cp14_read_reg,
701 xscale_cp14_write_reg);
702 //chy: 2003-08-24.
703 ARMul_CoProAttach (state, 15, xscale_cp15_init,
704 xscale_cp15_exit, xscale_cp15_ldc,
705 xscale_cp15_stc, xscale_cp15_mrc,
706 xscale_cp15_mcr, NULL, NULL, xscale_cp15_cdp,
707 xscale_cp15_read_reg,
708 xscale_cp15_write_reg);
709 }
710 else if (state->is_v6) {
711 ARMul_CoProAttach (state, 10, VFPInit, NULL, VFPLDC, VFPSTC,
712 VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
713 ARMul_CoProAttach (state, 11, VFPInit, NULL, VFPLDC, VFPSTC,
714 VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL);
715
716 ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
717 MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);
718 }
719 else { //all except xscale
720 ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL,
721 // MMUMRC, MMUMCR, NULL, MMURead, MMUWrite);
722 MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);
723 }
724//chy 2003-09-03 do it in future!!!!????
725#if 0 239#if 0
726 if (state->is_iWMMXt) { 240 if (state->is_iWMMXt) {
727 ARMul_CoProAttach (state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC, 241 ARMul_CoProAttach(state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC,
728 NULL, NULL, IwmmxtCDP, NULL, NULL); 242 NULL, NULL, IwmmxtCDP, NULL, NULL);
729 243
730 ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL, 244 ARMul_CoProAttach(state, 1, NULL, NULL, NULL, NULL,
731 IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, 245 IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL,
732 NULL); 246 NULL);
733 } 247 }
734#endif 248#endif
735 //----------------------------------------------------------------------------- 249 /* No handlers below here. */
736 //chy 2004-05-25, found the user/system code visit CP 1,2, so I add below code. 250
737 ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL, 251 /* Call all the initialisation routines. */
738 ValMRC, ValMCR, NULL, NULL, NULL, NULL, NULL); 252 for (i = 0; i < 16; i++)
739 ARMul_CoProAttach (state, 2, NULL, NULL, ValLDC, ValSTC, 253 if (state->CPInit[i])
740 NULL, NULL, NULL, NULL, NULL, NULL, NULL); 254 (state->CPInit[i]) (state);
741 //------------------------------------------------------------------------------ 255
742 /* No handlers below here. */ 256 return TRUE;
743
744 /* Call all the initialisation routines. */
745 for (i = 0; i < 16; i++)
746 if (state->CPInit[i])
747 (state->CPInit[i]) (state);
748
749 return TRUE;
750} 257}
751 258
752/* Install co-processor finalisation routines in this routine. */ 259/* Install co-processor finalisation routines in this routine. */
753 260
754void 261void
755ARMul_CoProExit (ARMul_State * state) 262ARMul_CoProExit(ARMul_State * state)
756{ 263{
757 register unsigned i; 264 register unsigned i;
758 265
759 for (i = 0; i < 16; i++) 266 for (i = 0; i < 16; i++)
760 if (state->CPExit[i]) 267 if (state->CPExit[i])
761 (state->CPExit[i]) (state); 268 (state->CPExit[i]) (state);
762 269
763 for (i = 0; i < 16; i++) /* Detach all handlers. */ 270 for (i = 0; i < 16; i++) /* Detach all handlers. */
764 ARMul_CoProDetach (state, i); 271 ARMul_CoProDetach(state, i);
765} 272}
766 273
767/* Routines to hook Co-processors into ARMulator. */ 274/* Routines to hook Co-processors into ARMulator. */
768 275
769void 276void
770ARMul_CoProAttach (ARMul_State * state, 277ARMul_CoProAttach(ARMul_State * state,
771 unsigned number, 278unsigned number,
772 ARMul_CPInits * init, 279ARMul_CPInits * init,
773 ARMul_CPExits * exit, 280ARMul_CPExits * exit,
774 ARMul_LDCs * ldc, 281ARMul_LDCs * ldc,
775 ARMul_STCs * stc, 282ARMul_STCs * stc,
776 ARMul_MRCs * mrc, 283ARMul_MRCs * mrc,
777 ARMul_MCRs * mcr, 284ARMul_MCRs * mcr,
778 ARMul_MRRCs * mrrc, 285ARMul_MRRCs * mrrc,
779 ARMul_MCRRs * mcrr, 286ARMul_MCRRs * mcrr,
780 ARMul_CDPs * cdp, 287ARMul_CDPs * cdp,
781 ARMul_CPReads * read, ARMul_CPWrites * write) 288ARMul_CPReads * read, ARMul_CPWrites * write)
782{
783 if (init != NULL)
784 state->CPInit[number] = init;
785 if (exit != NULL)
786 state->CPExit[number] = exit;
787 if (ldc != NULL)
788 state->LDC[number] = ldc;
789 if (stc != NULL)
790 state->STC[number] = stc;
791 if (mrc != NULL)
792 state->MRC[number] = mrc;
793 if (mcr != NULL)
794 state->MCR[number] = mcr;
795 if (mrrc != NULL)
796 state->MRRC[number] = mrrc;
797 if (mcrr != NULL)
798 state->MCRR[number] = mcrr;
799 if (cdp != NULL)
800 state->CDP[number] = cdp;
801 if (read != NULL)
802 state->CPRead[number] = read;
803 if (write != NULL)
804 state->CPWrite[number] = write;
805}
806
807void
808ARMul_CoProDetach (ARMul_State * state, unsigned number)
809{ 289{
810 ARMul_CoProAttach (state, number, NULL, NULL, 290 if (init != NULL)
811 NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R, 291 state->CPInit[number] = init;
812 NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL); 292 if (exit != NULL)
813 293 state->CPExit[number] = exit;
814 state->CPInit[number] = NULL; 294 if (ldc != NULL)
815 state->CPExit[number] = NULL; 295 state->LDC[number] = ldc;
816 state->CPRead[number] = NULL; 296 if (stc != NULL)
817 state->CPWrite[number] = NULL; 297 state->STC[number] = stc;
298 if (mrc != NULL)
299 state->MRC[number] = mrc;
300 if (mcr != NULL)
301 state->MCR[number] = mcr;
302 if (mrrc != NULL)
303 state->MRRC[number] = mrrc;
304 if (mcrr != NULL)
305 state->MCRR[number] = mcrr;
306 if (cdp != NULL)
307 state->CDP[number] = cdp;
308 if (read != NULL)
309 state->CPRead[number] = read;
310 if (write != NULL)
311 state->CPWrite[number] = write;
818} 312}
819 313
820//chy 2003-09-03:below funs just replace the old ones
821
822/* Set the XScale FSR and FAR registers. */
823
824void 314void
825XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far) 315ARMul_CoProDetach(ARMul_State * state, unsigned number)
826{
827 //if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0)
828 if (!state->is_XScale)
829 return;
830 //assume opcode2=0 crm =0
831 xscale_cp15_write_reg (state, 5, fsr);
832 xscale_cp15_write_reg (state, 6, _far);
833}
834
835//chy 2003-09-03 seems 0 is CANT, 1 is DONE ????
836int
837XScale_debug_moe (ARMul_State * state, int moe)
838{ 316{
839 //chy 2003-09-03 , W/R CP14 reg, now it's no use ???? 317 ARMul_CoProAttach(state, number, NULL, NULL,
840 printf ("SKYEYE: XScale_debug_moe called !!!!\n"); 318 NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R,
841 return 1; 319 NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL);
320
321 state->CPInit[number] = NULL;
322 state->CPExit[number] = NULL;
323 state->CPRead[number] = NULL;
324 state->CPWrite[number] = NULL;
842} 325}
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 @@
18 18
19//#include <util.h> // DEBUG() 19//#include <util.h> // DEBUG()
20 20
21#include "arm_regformat.h" 21#include "core/arm/skyeye_common/arm_regformat.h"
22#include "armdefs.h" 22#include "core/arm/skyeye_common/armdefs.h"
23#include "armemu.h" 23#include "core/arm/skyeye_common/armemu.h"
24#include "core/hle/hle.h" 24#include "core/hle/hle.h"
25 25
26//#include "svc.h" 26//#include "svc.h"
@@ -28,9 +28,6 @@
28//ichfly 28//ichfly
29//#define callstacker 1 29//#define callstacker 1
30 30
31
32//#include "armos.h"
33
34//#include "skyeye_callback.h" 31//#include "skyeye_callback.h"
35//#include "skyeye_bus.h" 32//#include "skyeye_bus.h"
36//#include "sim_control.h" 33//#include "sim_control.h"
@@ -66,13 +63,6 @@ static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int);
66static void Handle_Load_Double (ARMul_State *, ARMword); 63static void Handle_Load_Double (ARMul_State *, ARMword);
67static void Handle_Store_Double (ARMul_State *, ARMword); 64static void Handle_Store_Double (ARMul_State *, ARMword);
68 65
69void
70XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far);
71int
72XScale_debug_moe (ARMul_State * state, int moe);
73unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
74 unsigned cpnum);
75
76static int 66static int
77handle_v6_insn (ARMul_State * state, ARMword instr); 67handle_v6_insn (ARMul_State * state, ARMword instr);
78 68
@@ -379,7 +369,7 @@ ARMul_Emulate26 (ARMul_State * state)
379#endif 369#endif
380{ 370{
381 /* The PC pipeline value depends on whether ARM 371 /* The PC pipeline value depends on whether ARM
382 or Thumb instructions are being 372 or Thumb instructions are being
383 d. */ 373 d. */
384 ARMword isize; 374 ARMword isize;
385 ARMword instr; /* The current instruction. */ 375 ARMword instr; /* The current instruction. */
@@ -541,6 +531,7 @@ ARMul_Emulate26 (ARMul_State * state)
541 state->AbortAddr = 1; 531 state->AbortAddr = 1;
542 532
543 instr = ARMul_LoadInstrN (state, pc, isize); 533 instr = ARMul_LoadInstrN (state, pc, isize);
534
544 //chy 2006-04-12, for ICE debug 535 //chy 2006-04-12, for ICE debug
545 have_bp=ARMul_ICE_debug(state,instr,pc); 536 have_bp=ARMul_ICE_debug(state,instr,pc);
546#if 0 537#if 0
@@ -565,6 +556,7 @@ ARMul_Emulate26 (ARMul_State * state)
565 } 556 }
566 printf("\n"); 557 printf("\n");
567#endif 558#endif
559
568 instr = ARMul_LoadInstrN (state, pc, isize); 560 instr = ARMul_LoadInstrN (state, pc, isize);
569 state->last_instr = state->CurrInstr; 561 state->last_instr = state->CurrInstr;
570 state->CurrInstr = instr; 562 state->CurrInstr = instr;
@@ -955,9 +947,8 @@ ARMul_Emulate26 (ARMul_State * state)
955 case t_decoded: 947 case t_decoded:
956 /* ARM instruction available. */ 948 /* ARM instruction available. */
957 //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp); 949 //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp);
958 950
959 if (armOp == 0xDEADC0DE) 951 if (armOp == 0xDEADC0DE) {
960 {
961 DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc); 952 DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc);
962 } 953 }
963 954
@@ -970,7 +961,6 @@ ARMul_Emulate26 (ARMul_State * state)
970 } 961 }
971 } 962 }
972#endif 963#endif
973
974 /* Check the condition codes. */ 964 /* Check the condition codes. */
975 if ((temp = TOPBITS (28)) == AL) { 965 if ((temp = TOPBITS (28)) == AL) {
976 /* Vile deed in the need for speed. */ 966 /* Vile deed in the need for speed. */
@@ -1127,6 +1117,7 @@ ARMul_Emulate26 (ARMul_State * state)
1127 1117
1128//chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it... 1118//chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it...
1129 1119
1120
1130 /* Actual execution of instructions begins here. */ 1121 /* Actual execution of instructions begins here. */
1131 /* If the condition codes don't match, stop here. */ 1122 /* If the condition codes don't match, stop here. */
1132 if (temp) { 1123 if (temp) {
@@ -2311,12 +2302,9 @@ mainswitch:
2311 if (state->Aborted) { 2302 if (state->Aborted) {
2312 TAKEABORT; 2303 TAKEABORT;
2313 } 2304 }
2314 if (enter) 2305 if (enter) {
2315 {
2316 state->Reg[DESTReg] = 0; 2306 state->Reg[DESTReg] = 0;
2317 } 2307 } else {
2318 else
2319 {
2320 state->Reg[DESTReg] = 1; 2308 state->Reg[DESTReg] = 1;
2321 } 2309 }
2322 break; 2310 break;
@@ -3066,7 +3054,27 @@ mainswitch:
3066 break; 3054 break;
3067 3055
3068 case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ 3056 case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */
3069 if (BIT (4)) { 3057 //ichfly PKHBT PKHTB todo check this
3058 if ((instr & 0x70) == 0x10) //pkhbt
3059 {
3060 u8 idest = BITS(12, 15);
3061 u8 rfis = BITS(16, 19);
3062 u8 rlast = BITS(0, 3);
3063 u8 ishi = BITS(7,11);
3064 state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000);
3065 break;
3066 }
3067 else if ((instr & 0x70) == 0x50)//pkhtb
3068 {
3069 u8 idest = BITS(12, 15);
3070 u8 rfis = BITS(16, 19);
3071 u8 rlast = BITS(0, 3);
3072 u8 ishi = BITS(7, 11);
3073 if (ishi == 0)ishi = 0x20;
3074 state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000);
3075 break;
3076 }
3077 else if (BIT (4)) {
3070#ifdef MODE32 3078#ifdef MODE32
3071 if (state->is_v6 3079 if (state->is_v6
3072 && handle_v6_insn (state, instr)) 3080 && handle_v6_insn (state, instr))
@@ -3678,7 +3686,13 @@ mainswitch:
3678 3686
3679 /* Co-Processor Data Transfers. */ 3687 /* Co-Processor Data Transfers. */
3680 case 0xc4: 3688 case 0xc4:
3681 if (state->is_v5) { 3689 if ((instr & 0x0FF00FF0) == 0xC400B10) //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0
3690 {
3691 state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)];
3692 state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)];
3693 break;
3694 }
3695 else if (state->is_v5) {
3682 /* Reading from R15 is UNPREDICTABLE. */ 3696 /* Reading from R15 is UNPREDICTABLE. */
3683 if (BITS (12, 15) == 15 || BITS (16, 19) == 15) 3697 if (BITS (12, 15) == 15 || BITS (16, 19) == 15)
3684 ARMul_UndefInstr (state, instr); 3698 ARMul_UndefInstr (state, instr);
@@ -3698,13 +3712,21 @@ mainswitch:
3698 break; 3712 break;
3699 3713
3700 case 0xc5: 3714 case 0xc5:
3701 if (state->is_v5) { 3715 if ((instr & 0x00000FF0) == 0xB10) //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0
3716 {
3717 state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1];
3718 state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1];
3719 break;
3720 }
3721 else if (state->is_v5) {
3702 /* Writes to R15 are UNPREDICATABLE. */ 3722 /* Writes to R15 are UNPREDICATABLE. */
3703 if (DESTReg == 15 || LHSReg == 15) 3723 if (DESTReg == 15 || LHSReg == 15)
3704 ARMul_UndefInstr (state, instr); 3724 ARMul_UndefInstr (state, instr);
3705 /* Is access to the coprocessor allowed ? */ 3725 /* Is access to the coprocessor allowed ? */
3706 else if (!CP_ACCESS_ALLOWED(state, CPNum)) 3726 else if (!CP_ACCESS_ALLOWED(state, CPNum))
3707 ARMul_UndefInstr (state, instr); 3727 {
3728 ARMul_UndefInstr(state, instr);
3729 }
3708 else { 3730 else {
3709 /* MRRC, ARMv5TE and up */ 3731 /* MRRC, ARMv5TE and up */
3710 ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); 3732 ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg]));
@@ -4062,9 +4084,11 @@ TEST_EMULATE:
4062 // continue; 4084 // continue;
4063 else if (state->Emulate != RUN) 4085 else if (state->Emulate != RUN)
4064 break; 4086 break;
4065 } 4087
4066 while (state->NumInstrsToExecute--); 4088 }
4067 4089
4090 while (state->NumInstrsToExecute);
4091exit:
4068 state->decoded = decoded; 4092 state->decoded = decoded;
4069 state->loaded = loaded; 4093 state->loaded = loaded;
4070 state->pc = pc; 4094 state->pc = pc;
@@ -5689,12 +5713,98 @@ L_stm_s_takeabort:
5689 case 0x3f: 5713 case 0x3f:
5690 printf ("Unhandled v6 insn: rbit\n"); 5714 printf ("Unhandled v6 insn: rbit\n");
5691 break; 5715 break;
5716#endif
5692 case 0x61: 5717 case 0x61:
5693 printf ("Unhandled v6 insn: sadd/ssub\n"); 5718 if ((instr & 0xFF0) == 0xf70)//ssub16
5719 {
5720 u8 tar = BITS(12, 15);
5721 u8 src1 = BITS(16, 19);
5722 u8 src2 = BITS(0, 3);
5723 s16 a1 = (state->Reg[src1] & 0xFFFF);
5724 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5725 s16 b1 = (state->Reg[src2] & 0xFFFF);
5726 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
5727 state->Reg[tar] = (a1 - a2)&0xFFFF | (((b1 - b2)&0xFFFF)<< 0x10);
5728 return 1;
5729 }
5730 else if ((instr & 0xFF0) == 0xf10)//sadd16
5731 {
5732 u8 tar = BITS(12, 15);
5733 u8 src1 = BITS(16, 19);
5734 u8 src2 = BITS(0, 3);
5735 s16 a1 = (state->Reg[src1] & 0xFFFF);
5736 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5737 s16 b1 = (state->Reg[src2] & 0xFFFF);
5738 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
5739 state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10);
5740 return 1;
5741 }
5742 else if ((instr & 0xFF0) == 0xf50)//ssax
5743 {
5744 u8 tar = BITS(12, 15);
5745 u8 src1 = BITS(16, 19);
5746 u8 src2 = BITS(0, 3);
5747 s16 a1 = (state->Reg[src1] & 0xFFFF);
5748 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5749 s16 b1 = (state->Reg[src2] & 0xFFFF);
5750 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
5751 state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
5752 return 1;
5753 }
5754 else if ((instr & 0xFF0) == 0xf30)//sasx
5755 {
5756 u8 tar = BITS(12, 15);
5757 u8 src1 = BITS(16, 19);
5758 u8 src2 = BITS(0, 3);
5759 s16 a1 = (state->Reg[src1] & 0xFFFF);
5760 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5761 s16 b1 = (state->Reg[src2] & 0xFFFF);
5762 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
5763 state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
5764 return 1;
5765 }
5766 else printf ("Unhandled v6 insn: sadd/ssub\n");
5694 break; 5767 break;
5695 case 0x62: 5768 case 0x62:
5696 printf ("Unhandled v6 insn: qadd/qsub\n"); 5769 if ((instr & 0xFF0) == 0xf70)//QSUB16
5770 {
5771 u8 tar = BITS(12, 15);
5772 u8 src1 = BITS(16, 19);
5773 u8 src2 = BITS(0, 3);
5774 s16 a1 = (state->Reg[src1] & 0xFFFF);
5775 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5776 s16 b1 = (state->Reg[src2] & 0xFFFF);
5777 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
5778 s32 res1 = (a1 - b1);
5779 s32 res2 = (a2 - b2);
5780 if (res1 > 0x7FFF) res1 = 0x7FFF;
5781 if (res2 > 0x7FFF) res2 = 0x7FFF;
5782 if (res1 < 0x7FFF) res1 = -0x8000;
5783 if (res2 < 0x7FFF) res2 = -0x8000;
5784 state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10);
5785 return 1;
5786 }
5787 else if ((instr & 0xFF0) == 0xf10)//QADD16
5788 {
5789 u8 tar = BITS(12, 15);
5790 u8 src1 = BITS(16, 19);
5791 u8 src2 = BITS(0, 3);
5792 s16 a1 = (state->Reg[src1] & 0xFFFF);
5793 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5794 s16 b1 = (state->Reg[src2] & 0xFFFF);
5795 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
5796 s32 res1 = (a1 + b1);
5797 s32 res2 = (a2 + b2);
5798 if (res1 > 0x7FFF) res1 = 0x7FFF;
5799 if (res2 > 0x7FFF) res2 = 0x7FFF;
5800 if (res1 < 0x7FFF) res1 = -0x8000;
5801 if (res2 < 0x7FFF) res2 = -0x8000;
5802 state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10);
5803 return 1;
5804 }
5805 else printf ("Unhandled v6 insn: qadd/qsub\n");
5697 break; 5806 break;
5807#if 0
5698 case 0x63: 5808 case 0x63:
5699 printf ("Unhandled v6 insn: shadd/shsub\n"); 5809 printf ("Unhandled v6 insn: shadd/shsub\n");
5700 break; 5810 break;
@@ -5712,10 +5822,65 @@ L_stm_s_takeabort:
5712 break; 5822 break;
5713#endif 5823#endif
5714 case 0x6c: 5824 case 0x6c:
5715 printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); 5825 if ((instr & 0xf03f0) == 0xf0070) //uxtb16
5826 {
5827 u8 src1 = BITS(0, 3);
5828 u8 tar = BITS(12, 15);
5829 u32 base = state->Reg[src1];
5830 u32 shamt = BITS(9,10)* 8;
5831 u32 in = ((base << (32 - shamt)) | (base >> shamt));
5832 state->Reg[tar] = in & 0x00FF00FF;
5833 return 1;
5834 }
5835 else
5836 printf ("Unhandled v6 insn: uxtb16/uxtab16\n");
5716 break; 5837 break;
5717 case 0x70: 5838 case 0x70:
5718 printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); 5839 if ((instr & 0xf0d0) == 0xf010)//smuad //ichfly
5840 {
5841 u8 tar = BITS(16, 19);
5842 u8 src1 = BITS(0, 3);
5843 u8 src2 = BITS(8, 11);
5844 u8 swap = BIT(5);
5845 s16 a1 = (state->Reg[src1] & 0xFFFF);
5846 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5847 s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
5848 s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
5849 state->Reg[tar] = a1*a2 + b1*b2;
5850 return 1;
5851
5852 }
5853 else if ((instr & 0xf0d0) == 0xf050)//smusd
5854 {
5855 u8 tar = BITS(16, 19);
5856 u8 src1 = BITS(0, 3);
5857 u8 src2 = BITS(8, 11);
5858 u8 swap = BIT(5);
5859 s16 a1 = (state->Reg[src1] & 0xFFFF);
5860 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5861 s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
5862 s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
5863 state->Reg[tar] = a1*a2 - b1*b2;
5864 return 1;
5865 }
5866 else if ((instr & 0xd0) == 0x10)//smlad
5867 {
5868 u8 tar = BITS(16, 19);
5869 u8 src1 = BITS(0, 3);
5870 u8 src2 = BITS(8, 11);
5871 u8 src3 = BITS(12, 15);
5872 u8 swap = BIT(5);
5873
5874 u32 a3 = state->Reg[src3];
5875
5876 s16 a1 = (state->Reg[src1] & 0xFFFF);
5877 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5878 s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
5879 s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
5880 state->Reg[tar] = a1*a2 + b1*b2 + a3;
5881 return 1;
5882 }
5883 else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n");
5719 break; 5884 break;
5720 case 0x74: 5885 case 0x74:
5721 printf ("Unhandled v6 insn: smlald/smlsld\n"); 5886 printf ("Unhandled v6 insn: smlald/smlsld\n");
@@ -5753,13 +5918,10 @@ L_stm_s_takeabort:
5753 if (state->Aborted) { 5918 if (state->Aborted) {
5754 TAKEABORT; 5919 TAKEABORT;
5755 } 5920 }
5756 5921
5757 if (enter) 5922 if (enter) {
5758 {
5759 state->Reg[DESTReg] = 0; 5923 state->Reg[DESTReg] = 0;
5760 } 5924 } else {
5761 else
5762 {
5763 state->Reg[DESTReg] = 1; 5925 state->Reg[DESTReg] = 1;
5764 } 5926 }
5765 5927
@@ -5798,12 +5960,9 @@ L_stm_s_takeabort:
5798 } 5960 }
5799 5961
5800 5962
5801 if (enter) 5963 if (enter) {
5802 {
5803 state->Reg[DESTReg] = 0; 5964 state->Reg[DESTReg] = 0;
5804 } 5965 } else {
5805 else
5806 {
5807 state->Reg[DESTReg] = 1; 5966 state->Reg[DESTReg] = 1;
5808 } 5967 }
5809 5968
@@ -5856,8 +6015,25 @@ L_stm_s_takeabort:
5856 6015
5857 case 0x01: 6016 case 0x01:
5858 case 0xf3: 6017 case 0xf3:
5859 printf ("Unhandled v6 insn: ssat\n"); 6018 //ichfly
5860 return 0; 6019 //SSAT16
6020 {
6021 u8 tar = BITS(12,15);
6022 u8 src = BITS(0, 3);
6023 u8 val = BITS(16, 19) + 1;
6024 s16 a1 = (state->Reg[src]);
6025 s16 a2 = (state->Reg[src] >> 0x10);
6026 s16 min = (s16)(0x8000) >> (16 - val);
6027 s16 max = 0x7FFF >> (16 - val);
6028 if (min > a1) a1 = min;
6029 if (max < a1) a1 = max;
6030 if (min > a2) a2 = min;
6031 if (max < a2) a2 = max;
6032 u32 temp2 = ((u32)(a2)) << 0x10;
6033 state->Reg[tar] = (a1&0xFFFF) | (temp2);
6034 }
6035
6036 return 1;
5861 default: 6037 default:
5862 break; 6038 break;
5863 } 6039 }
@@ -5947,8 +6123,21 @@ L_stm_s_takeabort:
5947 6123
5948 case 0x01: 6124 case 0x01:
5949 case 0xf3: 6125 case 0xf3:
5950 printf ("Unhandled v6 insn: usat\n"); 6126 //ichfly
5951 return 0; 6127 //USAT16
6128 {
6129 u8 tar = BITS(12, 15);
6130 u8 src = BITS(0, 3);
6131 u8 val = BITS(16, 19);
6132 s16 a1 = (state->Reg[src]);
6133 s16 a2 = (state->Reg[src] >> 0x10);
6134 s16 max = 0xFFFF >> (16 - val);
6135 if (max < a1) a1 = max;
6136 if (max < a2) a2 = max;
6137 u32 temp2 = ((u32)(a2)) << 0x10;
6138 state->Reg[tar] = (a1 & 0xFFFF) | (temp2);
6139 }
6140 return 1;
5952 default: 6141 default:
5953 break; 6142 break;
5954 } 6143 }
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 @@
17 17
18//#include <unistd.h> 18//#include <unistd.h>
19 19
20#include "core/arm/interpreter/armdefs.h" 20#include "core/arm/skyeye_common/armdefs.h"
21#include "core/arm/interpreter/armemu.h" 21#include "core/arm/skyeye_common/armemu.h"
22 22
23/***************************************************************************\ 23/***************************************************************************\
24* Definitions for the emulator architecture * 24* 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 @@
1/*
2 armmmu.c - Memory Management Unit emulation.
3 ARMulator extensions for the ARM7100 family.
4 Copyright (C) 1999 Ben Williamson
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#include <assert.h>
22#include <string.h>
23#include "armdefs.h"
24/* two header for arm disassemble */
25//#include "skyeye_arch.h"
26#include "armcpu.h"
27
28
29extern mmu_ops_t xscale_mmu_ops;
30exception_t arm_mmu_write(short size, u32 addr, uint32_t *value);
31exception_t arm_mmu_read(short size, u32 addr, uint32_t *value);
32#define MMU_OPS (state->mmu.ops)
33ARMword skyeye_cachetype = -1;
34
35int
36mmu_init (ARMul_State * state)
37{
38 int ret;
39
40 state->mmu.control = 0x70;
41 state->mmu.translation_table_base = 0xDEADC0DE;
42 state->mmu.domain_access_control = 0xDEADC0DE;
43 state->mmu.fault_status = 0;
44 state->mmu.fault_address = 0;
45 state->mmu.process_id = 0;
46
47 switch (state->cpu->cpu_val & state->cpu->cpu_mask) {
48 //case SA1100:
49 //case SA1110:
50 // NOTICE_LOG(ARM11, "SKYEYE: use sa11xx mmu ops\n");
51 // state->mmu.ops = sa_mmu_ops;
52 // break;
53 //case PXA250:
54 //case PXA270: //xscale
55 // NOTICE_LOG(ARM11, "SKYEYE: use xscale mmu ops\n");
56 // state->mmu.ops = xscale_mmu_ops;
57 // break;
58 //case 0x41807200: //arm720t
59 //case 0x41007700: //arm7tdmi
60 //case 0x41007100: //arm7100
61 // NOTICE_LOG(ARM11, "SKYEYE: use arm7100 mmu ops\n");
62 // state->mmu.ops = arm7100_mmu_ops;
63 // break;
64 //case 0x41009200:
65 // NOTICE_LOG(ARM11, "SKYEYE: use arm920t mmu ops\n");
66 // state->mmu.ops = arm920t_mmu_ops;
67 // break;
68 //case 0x41069260:
69 // NOTICE_LOG(ARM11, "SKYEYE: use arm926ejs mmu ops\n");
70 // state->mmu.ops = arm926ejs_mmu_ops;
71 // break;
72 /* case 0x560f5810: */
73 case 0x0007b000:
74 NOTICE_LOG(ARM11, "SKYEYE: use arm11jzf-s mmu ops\n");
75 state->mmu.ops = arm1176jzf_s_mmu_ops;
76 break;
77
78 default:
79 ERROR_LOG (ARM11,
80 "SKYEYE: armmmu.c : mmu_init: unknown cpu_val&cpu_mask 0x%x\n",
81 state->cpu->cpu_val & state->cpu->cpu_mask);
82 break;
83
84 };
85 ret = state->mmu.ops.init (state);
86 state->mmu_inited = (ret == 0);
87 /* initialize mmu_read and mmu_write for disassemble */
88 //skyeye_config_t *config = get_current_config();
89 //generic_arch_t *arch_instance = get_arch_instance(config->arch->arch_name);
90 //arch_instance->mmu_read = arm_mmu_read;
91 //arch_instance->mmu_write = arm_mmu_write;
92
93 return ret;
94}
95
96int
97mmu_reset (ARMul_State * state)
98{
99 if (state->mmu_inited)
100 mmu_exit (state);
101 return mmu_init (state);
102}
103
104void
105mmu_exit (ARMul_State * state)
106{
107 MMU_OPS.exit (state);
108 state->mmu_inited = 0;
109}
110
111fault_t
112mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data)
113{
114 return MMU_OPS.read_byte (state, virt_addr, data);
115};
116
117fault_t
118mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data)
119{
120 return MMU_OPS.read_halfword (state, virt_addr, data);
121};
122
123fault_t
124mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data)
125{
126 return MMU_OPS.read_word (state, virt_addr, data);
127};
128
129fault_t
130mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data)
131{
132 fault_t fault;
133 //static int count = 0;
134 //count ++;
135 fault = MMU_OPS.write_byte (state, virt_addr, data);
136 return fault;
137}
138
139fault_t
140mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data)
141{
142 fault_t fault;
143 //static int count = 0;
144 //count ++;
145 fault = MMU_OPS.write_halfword (state, virt_addr, data);
146 return fault;
147}
148
149fault_t
150mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data)
151{
152 fault_t fault;
153 fault = MMU_OPS.write_word (state, virt_addr, data);
154
155 /*used for debug for MMU*
156
157 if (!fault){
158 ARMword tmp;
159
160 if (mmu_read_word(state, virt_addr, &tmp)){
161 err_msg("load back\n");
162 exit(-1);
163 }else{
164 if (tmp != data){
165 err_msg("load back not equal %d %x\n", count, virt_addr);
166 }
167 }
168 }
169 */
170
171 return fault;
172};
173
174fault_t
175mmu_load_instr (ARMul_State * state, ARMword virt_addr, ARMword * instr)
176{
177 return MMU_OPS.load_instr (state, virt_addr, instr);
178}
179
180ARMword
181mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value)
182{
183 return MMU_OPS.mrc (state, instr, value);
184}
185
186void
187mmu_mcr (ARMul_State * state, ARMword instr, ARMword value)
188{
189 MMU_OPS.mcr (state, instr, value);
190}
191
192/*ywc 20050416*/
193int
194mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr)
195{
196 return (MMU_OPS.v2p_dbct (state, virt_addr, phys_addr));
197}
198
199//
200//
201///* dis_mmu_read for disassemble */
202//exception_t arm_mmu_read(short size, uint32_t addr, uint32_t * value)
203//{
204// ARMul_State *state;
205// ARM_CPU_State *cpu = get_current_cpu();
206// state = &cpu->core[0];
207// switch(size){
208// case 8:
209// MMU_OPS.read_byte (state, addr, value);
210// break;
211// case 16:
212// case 32:
213// break;
214// default:
215// ERROR_LOG(ARM11, "Error size %d", size);
216// break;
217// }
218// return No_exp;
219//}
220///* dis_mmu_write for disassemble */
221//exception_t arm_mmu_write(short size, uint32_t addr, uint32_t *value)
222//{
223// ARMul_State *state;
224// ARM_CPU_State *cpu = get_current_cpu();
225// state = &cpu->core[0];
226// switch(size){
227// case 8:
228// MMU_OPS.write_byte (state, addr, value);
229// break;
230// case 16:
231// case 32:
232// break;
233// default:
234// printf("In %s error size %d Line %d\n", __func__, size, __LINE__);
235// break;
236// }
237// return No_exp;
238//}
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 @@
1/* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18/* This file contains a model of Demon, ARM Ltd's Debug Monitor,
19including all the SWI's required to support the C library. The code in
20it is not really for the faint-hearted (especially the abort handling
21code), but it is a complete example. Defining NOOS will disable all the
22fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI
230x11 to halt the emulator. */
24
25//chy 2005-09-12 disable below line
26//#include "config.h"
27
28#include <time.h>
29#include <errno.h>
30#include <string.h>
31#include "skyeye_defs.h"
32#ifndef __USE_LARGEFILE64
33#define __USE_LARGEFILE64 /* When use 64 bit large file need define it! for stat64*/
34#endif
35#include <fcntl.h>
36#include <sys/stat.h>
37
38
39#ifndef O_RDONLY
40#define O_RDONLY 0
41#endif
42#ifndef O_WRONLY
43#define O_WRONLY 1
44#endif
45#ifndef O_RDWR
46#define O_RDWR 2
47#endif
48#ifndef O_BINARY
49#define O_BINARY 0
50#endif
51
52#ifdef __STDC__
53#define unlink(s) remove(s)
54#endif
55
56#ifdef HAVE_UNISTD_H
57#include <unistd.h> /* For SEEK_SET etc */
58#endif
59
60#ifdef __riscos
61extern int _fisatty (FILE *);
62#define isatty_(f) _fisatty(f)
63#else
64#ifdef __ZTC__
65#include <io.h>
66#define isatty_(f) isatty((f)->_file)
67#else
68#ifdef macintosh
69#include <ioctl.h>
70#define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL))
71#else
72#define isatty_(f) isatty (fileno (f))
73#endif
74#endif
75#endif
76
77#include "armdefs.h"
78#include "armos.h"
79#include "armemu.h"
80
81#ifndef NOOS
82#ifndef VALIDATE
83/* #ifndef ASIM */
84//chy 2005-09-12 disable below line
85//#include "armfpe.h"
86/* #endif */
87#endif
88#endif
89
90#define DUMP_SYSCALL 0
91#define dump(...) do { if (DUMP_SYSCALL) printf(__VA_ARGS__); } while(0)
92//#define debug(...) printf(__VA_ARGS__);
93#define debug(...) ;
94
95extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number);
96
97#ifndef FOPEN_MAX
98#define FOPEN_MAX 64
99#endif
100
101/***************************************************************************\
102* OS private Information *
103\***************************************************************************/
104
105unsigned arm_dyncom_SWI(ARMul_State * state, ARMword number)
106{
107 return ARMul_OSHandleSWI(state, number);
108}
109
110//mmap_area_t *mmap_global = NULL;
111
112static int translate_open_mode[] = {
113 O_RDONLY, /* "r" */
114 O_RDONLY + O_BINARY, /* "rb" */
115 O_RDWR, /* "r+" */
116 O_RDWR + O_BINARY, /* "r+b" */
117 O_WRONLY + O_CREAT + O_TRUNC, /* "w" */
118 O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */
119 O_RDWR + O_CREAT + O_TRUNC, /* "w+" */
120 O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */
121 O_WRONLY + O_APPEND + O_CREAT, /* "a" */
122 O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */
123 O_RDWR + O_APPEND + O_CREAT, /* "a+" */
124 O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */
125};
126//
127//static void
128//SWIWrite0 (ARMul_State * state, ARMword addr)
129//{
130// ARMword temp;
131//
132// //while ((temp = ARMul_ReadByte (state, addr++)) != 0)
133// while(1){
134// mem_read(8, addr++, &temp);
135// if(temp != 0)
136// (void) fputc ((char) temp, stdout);
137// else
138// break;
139// }
140//}
141//
142//static void
143//WriteCommandLineTo (ARMul_State * state, ARMword addr)
144//{
145// ARMword temp;
146// char *cptr = state->CommandLine;
147// if (cptr == NULL)
148// cptr = "\0";
149// do {
150// temp = (ARMword) * cptr++;
151// //ARMul_WriteByte (state, addr++, temp);
152// mem_write(8, addr++, temp);
153// }
154// while (temp != 0);
155//}
156//
157//static void
158//SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags)
159//{
160// char dummy[2000];
161// int flags;
162// int i;
163//
164// for (i = 0; (dummy[i] = ARMul_ReadByte (state, name + i)); i++);
165// assert(SWIflags< (sizeof(translate_open_mode)/ sizeof(translate_open_mode[0])));
166// /* Now we need to decode the Demon open mode */
167// flags = translate_open_mode[SWIflags];
168// flags = SWIflags;
169//
170// /* Filename ":tt" is special: it denotes stdin/out */
171// if (strcmp (dummy, ":tt") == 0) {
172// if (flags == O_RDONLY) /* opening tty "r" */
173// state->Reg[0] = 0; /* stdin */
174// else
175// state->Reg[0] = 1; /* stdout */
176// }
177// else {
178// state->Reg[0] = (int) open (dummy, flags, 0666);
179// }
180//}
181//
182//static void
183//SWIread (ARMul_State * state, ARMword f, ARMword ptr, ARMword len)
184//{
185// int res;
186// int i;
187// char *local = (char*) malloc (len);
188//
189// if (local == NULL) {
190// fprintf (stderr,
191// "sim: Unable to read 0x%ulx bytes - out of memory\n",
192// len);
193// return;
194// }
195//
196// res = read (f, local, len);
197// if (res > 0)
198// for (i = 0; i < res; i++)
199// //ARMul_WriteByte (state, ptr + i, local[i]);
200// mem_write(8, ptr + i, local[i]);
201// free (local);
202// //state->Reg[0] = res == -1 ? -1 : len - res;
203// state->Reg[0] = res;
204//}
205//
206//static void
207//SWIwrite (ARMul_State * state, ARMword f, ARMword ptr, ARMword len)
208//{
209// int res;
210// ARMword i;
211// char *local = malloc (len);
212//
213// if (local == NULL) {
214// fprintf (stderr,
215// "sim: Unable to write 0x%lx bytes - out of memory\n",
216// (long unsigned int) len);
217// return;
218// }
219//
220// for (i = 0; i < len; i++){
221// //local[i] = ARMul_ReadByte (state, ptr + i);
222// ARMword data;
223// mem_read(8, ptr + i, &data);
224// local[i] = data & 0xFF;
225// }
226//
227// res = write (f, local, len);
228// //state->Reg[0] = res == -1 ? -1 : len - res;
229// state->Reg[0] = res;
230// free (local);
231//}
232
233//static void
234//SWIflen (ARMul_State * state, ARMword fh)
235//{
236// ARMword addr;
237//
238// if (fh == 0 || fh > FOPEN_MAX) {
239// state->Reg[0] = -1L;
240// return;
241// }
242//
243// addr = lseek (fh, 0, SEEK_CUR);
244//
245// state->Reg[0] = lseek (fh, 0L, SEEK_END);
246// (void) lseek (fh, addr, SEEK_SET);
247//
248//}
249
250/***************************************************************************\
251* The emulator calls this routine when a SWI instruction is encuntered. The *
252* parameter passed is the SWI number (lower 24 bits of the instruction). *
253\***************************************************************************/
254/* ahe-ykl information is retrieved from elf header and the starting value of
255 brk_static is in sky_info_t */
256
257/* brk static hold the value of brk */
258static uint32_t brk_static = -1;
259
260unsigned
261ARMul_OSHandleSWI (ARMul_State * state, ARMword number)
262{
263 number &= 0xfffff;
264 ARMword addr, temp;
265
266 switch (number) {
267// case SWI_Syscall:
268// if (state->Reg[7] != 0)
269// return ARMul_OSHandleSWI(state, state->Reg[7]);
270// else
271// return FALSE;
272// case SWI_Read:
273// SWIread (state, state->Reg[0], state->Reg[1], state->Reg[2]);
274// return TRUE;
275//
276// case SWI_GetUID32:
277// state->Reg[0] = getuid();
278// return TRUE;
279//
280// case SWI_GetGID32:
281// state->Reg[0] = getgid();
282// return TRUE;
283//
284// case SWI_GetEUID32:
285// state->Reg[0] = geteuid();
286// return TRUE;
287//
288// case SWI_GetEGID32:
289// state->Reg[0] = getegid();
290// return TRUE;
291//
292// case SWI_Write:
293// SWIwrite (state, state->Reg[0], state->Reg[1], state->Reg[2]);
294// return TRUE;
295//
296// case SWI_Open:
297// SWIopen (state, state->Reg[0], state->Reg[1]);
298// return TRUE;
299//
300// case SWI_Close:
301// state->Reg[0] = close (state->Reg[0]);
302// return TRUE;
303//
304// case SWI_Seek:{
305// /* We must return non-zero for failure */
306// state->Reg[0] =
307// lseek (state->Reg[0], state->Reg[1],
308// SEEK_SET);
309// return TRUE;
310// }
311//
312// case SWI_ExitGroup:
313// case SWI_Exit:
314// {
315// struct timeval tv;
316// //gettimeofday(&tv,NULL);
317// //printf("In %s, %d sec, %d usec\n", __FUNCTION__, tv.tv_sec, tv.tv_usec);
318// printf("passed %d sec, %lld usec\n", get_clock_sec(), get_clock_us());
319//
320// /* quit here */
321// run_command("quit");
322// return TRUE;
323// }
324// case SWI_Times:{
325// uint32_t dest = state->Reg[0];
326// struct tms now;
327// struct target_tms32 nowret;
328//
329// uint32_t ret = times(&now);
330//
331// if (ret == -1){
332// debug("syscall %s error %d\n", "SWI_Times", ret);
333// state->Reg[0] = ret;
334// return FALSE;
335// }
336//
337// nowret.tms_cstime = now.tms_cstime;
338// nowret.tms_cutime = now.tms_cutime;
339// nowret.tms_stime = now.tms_stime;
340// nowret.tms_utime = now.tms_utime;
341//
342// uint32_t offset;
343// for (offset = 0; offset < sizeof(nowret); offset++) {
344// bus_write(8, dest + offset, *((uint8_t *) &nowret + offset));
345// }
346//
347// state->Reg[0] = ret;
348// return TRUE;
349// }
350//
351// case SWI_Gettimeofday: {
352// uint32_t dest1 = state->Reg[0];
353// uint32_t dest2 = state->Reg[1]; // Unsure of this
354// struct timeval val;
355// struct timezone zone;
356// struct target_timeval32 valret;
357// struct target_timezone32 zoneret;
358//
359// uint32_t ret = gettimeofday(&val, &zone);
360// valret.tv_sec = val.tv_sec;
361// valret.tv_usec = val.tv_usec;
362// zoneret.tz_dsttime = zoneret.tz_dsttime;
363// zoneret.tz_minuteswest = zoneret.tz_minuteswest;
364//
365// if (ret == -1){
366// debug("syscall %s error %d\n", "SWI_Gettimeofday", ret);
367// state->Reg[0] = ret;
368// return FALSE;
369// }
370//
371// uint32_t offset;
372// if (dest1) {
373// for (offset = 0; offset < sizeof(valret); offset++) {
374// bus_write(8, dest1 + offset, *((uint8_t *) &valret + offset));
375// }
376// state->Reg[0] = ret;
377// }
378// if (dest2) {
379// for (offset = 0; offset < sizeof(zoneret); offset++) {
380// bus_write(8, dest2 + offset, *((uint8_t *) &zoneret + offset));
381// }
382// state->Reg[0] = ret;
383// }
384//
385// return TRUE;
386// }
387// case SWI_Brk:
388// /* initialize brk value */
389// /* suppose that brk_static doesn't reach 0xffffffff... */
390// if (brk_static == -1) {
391// brk_static = (get_skyeye_pref()->info).brk;
392// }
393//
394// /* FIXME there might be a need to do a mmap */
395//
396// if(state->Reg[0]){
397// if (get_skyeye_exec_info()->mmap_access) {
398// /* if new brk is greater than current brk, allocate memory */
399// if (state->Reg[0] > brk_static) {
400// uint32_t ret = mmap( (void *) brk_static, state->Reg[0] - brk_static,
401// PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0 );
402// if (ret != MAP_FAILED)
403// brk_static = ret;
404// }
405// }
406// brk_static = state->Reg[0];
407// //state->Reg[0] = 0; /* FIXME return value of brk set to be the address on success */
408// } else {
409// state->Reg[0] = brk_static;
410// }
411// return TRUE;
412//
413// case SWI_Break:
414// state->Emulate = FALSE;
415// return TRUE;
416//
417// case SWI_Mmap:{
418// int addr = state->Reg[0];
419// int len = state->Reg[1];
420// int prot = state->Reg[2];
421// int flag = state->Reg[3];
422// int fd = state->Reg[4];
423// int offset = state->Reg[5];
424// mmap_area_t *area = new_mmap_area(addr, len);
425// state->Reg[0] = area->bank.addr;
426// //printf("syscall %d mmap(0x%x,%x,0x%x,0x%x,%d,0x%x) = 0x%x\n",\
427// SWI_Mmap, addr, len, prot, flag, fd, offset, state->Reg[0]);
428// return TRUE;
429// }
430//
431// case SWI_Munmap:
432// state->Reg[0] = 0;
433// return TRUE;
434//
435// case SWI_Mmap2:{
436// int addr = state->Reg[0];
437// int len = state->Reg[1];
438// int prot = state->Reg[2];
439// int flag = state->Reg[3];
440// int fd = state->Reg[4];
441// int offset = state->Reg[5] * 4096; /* page offset */
442// mmap_area_t *area = new_mmap_area(addr, len);
443// state->Reg[0] = area->bank.addr;
444//
445// return TRUE;
446// }
447//
448// case SWI_Breakpoint:
449// //chy 2005-09-12 change below line
450// //state->EndCondition = RDIError_BreakpointReached;
451// //printf ("SKYEYE: in armos.c : should not come here!!!!\n");
452// state->EndCondition = 0;
453// /*modified by ksh to support breakpoiont*/
454// state->Emulate = STOP;
455// return (TRUE);
456// case SWI_Uname:
457// {
458// struct utsname *uts = (uintptr_t) state->Reg[0]; /* uname should write data in this address */
459// struct utsname utsbuf;
460// //printf("Uname size is %x\n", sizeof(utsbuf));
461// char *buf;
462// uintptr_t sp ; /* used as a temporary address */
463//
464//#define COPY_UTS_STRING(addr) \
465// buf = addr; \
466// while(*buf != NULL) { \
467// bus_write(8, sp, *buf); \
468// sp++; \
469// buf++; \
470// }
471//#define COPY_UTS(field) /*printf("%s: %s at %p\n", #field, utsbuf.field, uts->field);*/ \
472// sp = (uintptr_t) uts->field; \
473// COPY_UTS_STRING((&utsbuf)->field);
474//
475// if (uname(&utsbuf) < 0) {
476// printf("syscall uname: utsname error\n");
477// state->Reg[0] = -1;
478// return FALSE;
479// }
480//
481// /* FIXME for now, this is just the host system call
482// Some data should be missing, as it depends on
483// the version of utsname */
484// COPY_UTS(sysname);
485// COPY_UTS(nodename);
486// COPY_UTS(release);
487// COPY_UTS(version);
488// COPY_UTS(machine);
489//
490// state->Reg[0] = 0;
491// return TRUE;
492// }
493// case SWI_Fcntl:
494// {
495// uint32_t fd = state->Reg[0];
496// uint32_t cmd = state->Reg[1];
497// uint32_t arg = state->Reg[2];
498// uint32_t ret;
499//
500// switch(cmd){
501// case (F_GETFD):
502// {
503// ret = fcntl(fd, cmd, arg);
504// //printf("syscall fcntl for getfd not implemented, ret %d\n", ret);
505// state->Reg[0] = ret;
506// return FALSE;
507// }
508// default:
509// break;
510// }
511//
512// printf("syscall fcntl unimplemented fd %x cmd %x\n", fd, cmd);
513// state->Reg[0] = -1;
514// return FALSE;
515//
516// }
517// case SWI_Fstat64:
518// {
519// uint32_t dest = state->Reg[1];
520// uint32_t fd = state->Reg[0];
521// struct stat64 statbuf;
522// struct target_stat64 statret;
523// memset(&statret, 0, sizeof(struct target_stat64));
524// uint32_t ret = fstat64(fd, &statbuf);
525//
526// if (ret == -1){
527// printf("syscall %s returned error\n", "SWI_Fstat");
528// state->Reg[0] = ret;
529// return FALSE;
530// }
531//
532// /* copy statbuf to the process memory space
533// FIXME can't say if endian has an effect here */
534// uint32_t offset;
535// //printf("Fstat system is size %x\n", sizeof(statbuf));
536// //printf("Fstat target is size %x\n", sizeof(statret));
537//
538// /* we copy system structure data stat64 into arm fixed size structure target_stat64 */
539// statret.st_dev = statbuf.st_dev;
540// statret.st_ino = statbuf.st_ino;
541// statret.st_mode = statbuf.st_mode;
542// statret.st_nlink = statbuf.st_nlink;
543// statret.st_uid = statbuf.st_uid;
544// statret.st_gid = statbuf.st_gid;
545// statret.st_rdev = statbuf.st_rdev;
546// statret.st_size = statbuf.st_size;
547// statret.st_blksize = statbuf.st_blksize;
548// statret.st_blocks = statbuf.st_blocks;
549// statret.st32_atime = statbuf.st_atime;
550// statret.st32_mtime = statbuf.st_mtime;
551// statret.st32_ctime = statbuf.st_ctime;
552//
553// for (offset = 0; offset < sizeof(statret); offset++) {
554// bus_write(8, dest + offset, *((uint8_t *) &statret + offset));
555// }
556//
557// state->Reg[0] = ret;
558// return TRUE;
559// }
560// case SWI_Set_tls:
561// {
562// //printf("syscall set_tls unimplemented\n");
563// state->mmu.thread_uro_id = state->Reg[0];
564// state->CP15[CP15_THREAD_URO - CP15_BASE] = state->Reg[0];
565// state->Reg[0] = 0;
566// return FALSE;
567// }
568//#if 0
569// case SWI_Clock:
570// /* return number of centi-seconds... */
571// state->Reg[0] =
572//#ifdef CLOCKS_PER_SEC
573// (CLOCKS_PER_SEC >= 100)
574// ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100))
575// : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC);
576//#else
577// /* presume unix... clock() returns microseconds */
578// (ARMword) (clock () / 10000);
579//#endif
580// return (TRUE);
581//
582// case SWI_Time:
583// state->Reg[0] = (ARMword) time (NULL);
584// return (TRUE);
585// case SWI_Flen:
586// SWIflen (state, state->Reg[0]);
587// return (TRUE);
588//
589//#endif
590 default:
591
592 _dbg_assert_msg_(ARM11, false, "ImplementMe: ARMul_OSHandleSWI!");
593
594 return (FALSE);
595 }
596}
597//
598///**
599// * @brief For mmap syscall.A mmap_area is a memory bank. Get from ppc.
600// */
601//static mmap_area_t* new_mmap_area(int sim_addr, int len){
602// mmap_area_t *area = (mmap_area_t *)malloc(sizeof(mmap_area_t));
603// if(area == NULL){
604// printf("error, failed %s\n",__FUNCTION__);
605// exit(0);
606// }
607//#if FAST_MEMORY
608// if (mmap_next_base == -1)
609// {
610// mmap_next_base = get_skyeye_exec_info()->brk;
611// }
612//#endif
613//
614// memset(area, 0x0, sizeof(mmap_area_t));
615// area->bank.addr = mmap_next_base;
616// area->bank.len = len;
617// area->bank.bank_write = mmap_mem_write;
618// area->bank.bank_read = mmap_mem_read;
619// area->bank.type = MEMTYPE_RAM;
620// area->bank.objname = "mmap";
621// addr_mapping(&area->bank);
622//
623//#if FAST_MEMORY
624// if (get_skyeye_exec_info()->mmap_access)
625// {
626// /* FIXME check proper flags */
627// /* FIXME we may delete the need of banks up there */
628// uint32_t ret = mmap(mmap_next_base, len, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
629// mmap_next_base = ret;
630// }
631// area->mmap_addr = (uint8_t*)get_dma_addr(mmap_next_base);
632//#else
633// area->mmap_addr = malloc(len);
634// if(area->mmap_addr == NULL){
635// printf("error mmap malloc\n");
636// exit(0);
637// }
638// memset(area->mmap_addr, 0x0, len);
639//#endif
640//
641// area->next = NULL;
642// if(mmap_global){
643// area->next = mmap_global->next;
644// mmap_global->next = area;
645// }else{
646// mmap_global = area;
647// }
648// mmap_next_base = mmap_next_base + len;
649// return area;
650//}
651//
652//static mmap_area_t *get_mmap_area(int addr){
653// mmap_area_t *tmp = mmap_global;
654// while(tmp){
655// if ((tmp->bank.addr <= addr) && (tmp->bank.addr + tmp->bank.len > addr)){
656// return tmp;
657// }
658// tmp = tmp->next;
659// }
660// printf("cannot get mmap area:addr=0x%x\n", addr);
661// return NULL;
662//}
663//
664///**
665// * @brief the mmap_area bank write function. Get from ppc.
666// *
667// * @param size size to write, 8/16/32
668// * @param addr address to write
669// * @param value value to write
670// *
671// * @return sucess return 1,otherwise 0.
672// */
673//static char mmap_mem_write(short size, int addr, uint32_t value){
674// mmap_area_t *area_tmp = get_mmap_area(addr);
675// mem_bank_t *bank_tmp = &area_tmp->bank;
676// int offset = addr - bank_tmp->addr;
677// switch(size){
678// case 8:{
679// //uint8_t value_endian = value;
680// uint8_t value_endian = (uint8_t)value;
681// *(uint8_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian;
682// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian);
683// break;
684// }
685// case 16:{
686// //uint16_t value_endian = half_to_BE((uint16_t)value);
687// uint16_t value_endian = ((uint16_t)value);
688// *(uint16_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian;
689// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian);
690// break;
691// }
692// case 32:{
693// //uint32_t value_endian = word_to_BE((uint32_t)value);
694// uint32_t value_endian = ((uint32_t)value);
695// *(uint32_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian;
696// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian);
697// break;
698// }
699// default:
700// printf("invalid size %d\n",size);
701// return 0;
702// }
703// return 1;
704//}
705//
706///**
707// * @brief the mmap_area bank read function. Get from ppc.
708// *
709// * @param size size to read, 8/16/32
710// * @param addr address to read
711// * @param value value to read
712// *
713// * @return sucess return 1,otherwise 0.
714// */
715//static char mmap_mem_read(short size, int addr, uint32_t * value){
716// mmap_area_t *area_tmp = get_mmap_area(addr);
717// mem_bank_t *bank_tmp = &area_tmp->bank;
718// int offset = addr - bank_tmp->addr;
719// switch(size){
720// case 8:{
721// //*(uint8_t *)value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]);
722// *value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]);
723// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value);
724// break;
725// }
726// case 16:{
727// //*(uint16_t *)value = half_from_BE(*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]));
728// *value = (*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]));
729// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint16_t*)value);
730// break;
731// }
732// case 32:
733// //*value = (uint32_t)word_from_BE(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]));
734// *value = (uint32_t)(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]));
735// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value);
736// break;
737// default:
738// printf("invalid size %d\n",size);
739// return 0;
740// }
741// return 1;
742//}
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 @@
15 along with this program; if not, write to the Free Software 15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17 17
18//#include <util.h> 18#include "core/arm/skyeye_common/armdefs.h"
19 19#include "core/arm/skyeye_common/armemu.h"
20#include <string>
21#include "core/arm/interpreter/armdefs.h"
22#include "core/arm/interpreter/armemu.h"
23#include "core/hle/coprocessor.h"
24#include "core/arm/disassembler/arm_disasm.h" 20#include "core/arm/disassembler/arm_disasm.h"
21#include "core/mem_map.h"
25 22
26//#include "ansidecl.h"
27//#include "skyeye.h"
28//extern int skyeye_instr_debug;
29/* Definitions for the support routines. */
30 23
31static ARMword ModeToBank (ARMword); 24static ARMword ModeToBank (ARMword);
32static void EnvokeList (ARMul_State *, unsigned int, unsigned int); 25static void EnvokeList (ARMul_State *, unsigned int, unsigned int);
@@ -751,7 +744,7 @@ ARMword ARMul_MRC (ARMul_State * state, ARMword instr)
751 int cpopc = BITS(21, 23) & 0x7; 744 int cpopc = BITS(21, 23) & 0x7;
752 745
753 if (cn == 13 && cm == 0 && cp == 3) { //c13,c0,3; returns CPU svc buffer 746 if (cn == 13 && cm == 0 && cp == 3) { //c13,c0,3; returns CPU svc buffer
754 ARMword result = HLE::CallMRC(instr); 747 ARMword result = Memory::KERNEL_MEMORY_VADDR;
755 748
756 if (result != -1) { 749 if (result != -1) {
757 return result; 750 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
23freed as they might be needed again. A single area of memory may be 23freed as they might be needed again. A single area of memory may be
24defined to generate aborts. */ 24defined to generate aborts. */
25 25
26#include "armdefs.h" 26#include "core/arm/skyeye_common/armdefs.h"
27#include "skyeye_defs.h" 27#include "core/arm/skyeye_common/armemu.h"
28//#include "code_cov.h"
29 28
30#ifdef VALIDATE /* for running the validate suite */ 29#include "core/mem_map.h"
31#define TUBE 48 * 1024 * 1024 /* write a char on the screen */
32#define ABORTS 1
33#endif
34
35/* #define ABORTS */
36
37#ifdef ABORTS /* the memory system will abort */
38/* For the old test suite Abort between 32 Kbytes and 32 Mbytes
39 For the new test suite Abort between 8 Mbytes and 26 Mbytes */
40/* #define LOWABORT 32 * 1024
41#define HIGHABORT 32 * 1024 * 1024 */
42#define LOWABORT 8 * 1024 * 1024
43#define HIGHABORT 26 * 1024 * 1024
44
45#endif
46
47#define NUMPAGES 64 * 1024
48#define PAGESIZE 64 * 1024
49#define PAGEBITS 16
50#define OFFSETBITS 0xffff
51//chy 2003-08-19: seems no use ????
52int SWI_vector_installed = FALSE;
53extern ARMword skyeye_cachetype;
54
55/***************************************************************************\
56* Get a byte into Virtual Memory, maybe allocating the page *
57\***************************************************************************/
58static fault_t
59GetByte (ARMul_State * state, ARMword address, ARMword * data)
60{
61 fault_t fault;
62
63 fault = mmu_read_byte (state, address, data);
64 if (fault) {
65//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
66// printf("SKYEYE: GetByte fault %d \n", fault);
67 }
68 return fault;
69}
70
71/***************************************************************************\
72* Get a halfword into Virtual Memory, maybe allocating the page *
73\***************************************************************************/
74static fault_t
75GetHalfWord (ARMul_State * state, ARMword address, ARMword * data)
76{
77 fault_t fault;
78
79 fault = mmu_read_halfword (state, address, data);
80 if (fault) {
81//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
82// printf("SKYEYE: GetHalfWord fault %d \n", fault);
83 }
84 return fault;
85}
86
87/***************************************************************************\
88* Get a Word from Virtual Memory, maybe allocating the page *
89\***************************************************************************/
90 30
91static fault_t 31#define dumpstack 1
92GetWord (ARMul_State * state, ARMword address, ARMword * data) 32#define dumpstacksize 0x10
93{ 33#define maxdmupaddr 0x0033a850
94 fault_t fault;
95 34
96 fault = mmu_read_word (state, address, data); 35/*ARMword ARMul_GetCPSR (ARMul_State * state) {
97 if (fault) { 36return 0;
98//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
99#if 0
100/* XXX */ extern int hack;
101 hack = 1;
102#endif
103#if 0
104 printf ("mmu_read_word at 0x%08x: ", address);
105 switch (fault) {
106 case ALIGNMENT_FAULT:
107 printf ("ALIGNMENT_FAULT");
108 break;
109 case SECTION_TRANSLATION_FAULT:
110 printf ("SECTION_TRANSLATION_FAULT");
111 break;
112 case PAGE_TRANSLATION_FAULT:
113 printf ("PAGE_TRANSLATION_FAULT");
114 break;
115 case SECTION_DOMAIN_FAULT:
116 printf ("SECTION_DOMAIN_FAULT");
117 break;
118 case SECTION_PERMISSION_FAULT:
119 printf ("SECTION_PERMISSION_FAULT");
120 break;
121 case SUBPAGE_PERMISSION_FAULT:
122 printf ("SUBPAGE_PERMISSION_FAULT");
123 break;
124 default:
125 printf ("Unrecognized fault number!");
126 }
127 printf ("\tpc = 0x%08x\n", state->Reg[15]);
128#endif
129 }
130 return fault;
131} 37}
132 38ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode) {
133//2003-07-10 chy: lyh change 39return 0;
134/****************************************************************************\
135 * Load a Instrion Word into Virtual Memory *
136\****************************************************************************/
137static fault_t
138LoadInstr (ARMul_State * state, ARMword address, ARMword * instr)
139{
140 fault_t fault;
141 fault = mmu_load_instr (state, address, instr);
142 return fault;
143 //if (fault)
144 // log_msg("load_instr fault = %d, address = %x\n", fault, address);
145} 40}
41void ARMul_SetCPSR (ARMul_State * state, ARMword value) {
146 42
147/***************************************************************************\
148* Put a byte into Virtual Memory, maybe allocating the page *
149\***************************************************************************/
150static fault_t
151PutByte (ARMul_State * state, ARMword address, ARMword data)
152{
153 fault_t fault;
154
155 fault = mmu_write_byte (state, address, data);
156 if (fault) {
157//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
158// printf("SKYEYE: PutByte fault %d \n", fault);
159 }
160 return fault;
161} 43}
44void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) {
162 45
163/***************************************************************************\ 46}*/
164* Put a halfword into Virtual Memory, maybe allocating the page *
165\***************************************************************************/
166static fault_t
167PutHalfWord (ARMul_State * state, ARMword address, ARMword data)
168{
169 fault_t fault;
170 47
171 fault = mmu_write_halfword (state, address, data); 48void ARMul_Icycles(ARMul_State * state, unsigned number, ARMword address) {
172 if (fault) {
173//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
174// printf("SKYEYE: PutHalfWord fault %d \n", fault);
175 }
176 return fault;
177} 49}
178 50
179/***************************************************************************\ 51void ARMul_Ccycles(ARMul_State * state, unsigned number, ARMword address) {
180* Put a Word into Virtual Memory, maybe allocating the page *
181\***************************************************************************/
182
183static fault_t
184PutWord (ARMul_State * state, ARMword address, ARMword data)
185{
186 fault_t fault;
187
188 fault = mmu_write_word (state, address, data);
189 if (fault) {
190//chy 2003-07-11: sometime has fault, but linux can continue running !!!!????
191#if 0
192/* XXX */ extern int hack;
193 hack = 1;
194#endif
195#if 0
196 printf ("mmu_write_word at 0x%08x: ", address);
197 switch (fault) {
198 case ALIGNMENT_FAULT:
199 printf ("ALIGNMENT_FAULT");
200 break;
201 case SECTION_TRANSLATION_FAULT:
202 printf ("SECTION_TRANSLATION_FAULT");
203 break;
204 case PAGE_TRANSLATION_FAULT:
205 printf ("PAGE_TRANSLATION_FAULT");
206 break;
207 case SECTION_DOMAIN_FAULT:
208 printf ("SECTION_DOMAIN_FAULT");
209 break;
210 case SECTION_PERMISSION_FAULT:
211 printf ("SECTION_PERMISSION_FAULT");
212 break;
213 case SUBPAGE_PERMISSION_FAULT:
214 printf ("SUBPAGE_PERMISSION_FAULT");
215 break;
216 default:
217 printf ("Unrecognized fault number!");
218 }
219 printf ("\tpc = 0x%08x\n", state->Reg[15]);
220#endif
221 }
222 return fault;
223} 52}
224 53
225/***************************************************************************\ 54ARMword ARMul_LoadInstrS(ARMul_State * state, ARMword address, ARMword isize) {
226* Initialise the memory interface * 55 state->NumScycles++;
227\***************************************************************************/
228
229unsigned
230ARMul_MemoryInit (ARMul_State * state, unsigned int initmemsize)
231{
232 return TRUE;
233}
234
235/***************************************************************************\
236* Remove the memory interface *
237\***************************************************************************/
238
239void
240ARMul_MemoryExit (ARMul_State * state)
241{
242}
243
244/***************************************************************************\
245* ReLoad Instruction *
246\***************************************************************************/
247
248ARMword
249ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize)
250{
251 ARMword data;
252 fault_t fault;
253
254#ifdef ABORTS
255 if (address >= LOWABORT && address < HIGHABORT) {
256 ARMul_PREFETCHABORT (address);
257 return ARMul_ABORTWORD;
258 }
259 else {
260 ARMul_CLEARABORT;
261 }
262#endif
263#if 0
264 /* do profiling for code coverage */
265 if (skyeye_config.code_cov.prof_on)
266 cov_prof(EXEC_FLAG, address);
267#endif
268#if 1
269 if ((isize == 2) && (address & 0x2)) {
270 ARMword lo, hi;
271 if (!(skyeye_cachetype == INSTCACHE))
272 fault = GetHalfWord (state, address, &lo);
273 else
274 fault = LoadInstr (state, address, &lo);
275#if 0
276 if (!fault) {
277 if (!(skyeye_cachetype == INSTCACHE))
278 fault = GetHalfWord (state, address + isize, &hi);
279 else
280 fault = LoadInstr (state, address + isize, &hi);
281
282 }
283#endif
284 if (fault) {
285 ARMul_PREFETCHABORT (address);
286 return ARMul_ABORTWORD;
287 }
288 else {
289 ARMul_CLEARABORT;
290 }
291 return lo;
292#if 0
293 if (state->bigendSig == HIGH)
294 return (lo << 16) | (hi >> 16);
295 else
296 return ((hi & 0xFFFF) << 16) | (lo >> 16);
297#endif
298 }
299#endif
300 if (!(skyeye_cachetype == INSTCACHE))
301 fault = GetWord (state, address, &data);
302 else
303 fault = LoadInstr (state, address, &data);
304
305 if (fault) {
306
307 /* dyf add for s3c6410 no instcache temporary 2010.9.17 */
308 if (!(skyeye_cachetype == INSTCACHE)) {
309 /* set translation fault on prefetch abort */
310 state->mmu.fault_statusi = fault & 0xFF;
311 state->mmu.fault_address = address;
312 }
313 /* add end */
314
315 ARMul_PREFETCHABORT (address);
316 return ARMul_ABORTWORD;
317 }
318 else {
319 ARMul_CLEARABORT;
320 }
321
322 return data;
323}
324
325/***************************************************************************\
326* Load Instruction, Sequential Cycle *
327\***************************************************************************/
328
329ARMword
330ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize)
331{
332 state->NumScycles++;
333 56
334#ifdef HOURGLASS 57#ifdef HOURGLASS
335 if ((state->NumScycles & HOURGLASS_RATE) == 0) { 58 if ((state->NumScycles & HOURGLASS_RATE) == 0) {
336 HOURGLASS; 59 HOURGLASS;
337 } 60 }
338#endif 61#endif
339 62 if (isize == 2)
340 return ARMul_ReLoadInstr (state, address, isize); 63 return (u16)Memory::Read16(address);
64 else
65 return (u32)Memory::Read32(address);
341} 66}
342 67
343/***************************************************************************\ 68ARMword ARMul_LoadInstrN(ARMul_State * state, ARMword address, ARMword isize) {
344* Load Instruction, Non Sequential Cycle * 69 state->NumNcycles++;
345\***************************************************************************/
346
347ARMword
348ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize)
349{
350 state->NumNcycles++;
351 70
352 return ARMul_ReLoadInstr (state, address, isize); 71 if (isize == 2)
72 return (u16)Memory::Read16(address);
73 else
74 return (u32)Memory::Read32(address);
353} 75}
354 76
355/***************************************************************************\ 77ARMword ARMul_ReLoadInstr(ARMul_State * state, ARMword address, ARMword isize) {
356* Read Word (but don't tell anyone!) * 78 ARMword data;
357\***************************************************************************/
358 79
359ARMword 80 if ((isize == 2) && (address & 0x2)) {
360ARMul_ReadWord (ARMul_State * state, ARMword address) 81 ARMword lo;
361{ 82 lo = (u16)Memory::Read16(address);
362 ARMword data; 83 return lo;
363 fault_t fault; 84 }
364
365#ifdef ABORTS
366 if (address >= LOWABORT && address < HIGHABORT) {
367 ARMul_DATAABORT (address);
368 return ARMul_ABORTWORD;
369 }
370 else {
371 ARMul_CLEARABORT;
372 }
373#endif
374 85
375 fault = GetWord (state, address, &data); 86 data = (u32)Memory::Read32(address);
376 if (fault) { 87 return data;
377 state->mmu.fault_status =
378 (fault | (state->mmu.last_domain << 4)) & 0xFF;
379 state->mmu.fault_address = address;
380 ARMul_DATAABORT (address);
381 return ARMul_ABORTWORD;
382 }
383 else {
384 ARMul_CLEARABORT;
385 }
386 return data;
387} 88}
388 89
389/***************************************************************************\ 90ARMword ARMul_ReadWord(ARMul_State * state, ARMword address) {
390* Load Word, Sequential Cycle * 91 ARMword data;
391\***************************************************************************/ 92 data = Memory::Read32(address);
392 93 return data;
393ARMword
394ARMul_LoadWordS (ARMul_State * state, ARMword address)
395{
396 state->NumScycles++;
397
398 return ARMul_ReadWord (state, address);
399} 94}
400 95
401/***************************************************************************\ 96ARMword ARMul_LoadWordS(ARMul_State * state, ARMword address) {
402* Load Word, Non Sequential Cycle * 97 state->NumScycles++;
403\***************************************************************************/ 98 return ARMul_ReadWord(state, address);
404
405ARMword
406ARMul_LoadWordN (ARMul_State * state, ARMword address)
407{
408 state->NumNcycles++;
409
410 return ARMul_ReadWord (state, address);
411} 99}
412 100
413/***************************************************************************\ 101ARMword ARMul_LoadWordN(ARMul_State * state, ARMword address) {
414* Load Halfword, (Non Sequential Cycle) * 102 state->NumNcycles++;
415\***************************************************************************/ 103 return ARMul_ReadWord(state, address);
416
417ARMword
418ARMul_LoadHalfWord (ARMul_State * state, ARMword address)
419{
420 ARMword data;
421 fault_t fault;
422
423 state->NumNcycles++;
424 fault = GetHalfWord (state, address, &data);
425
426 if (fault) {
427 state->mmu.fault_status =
428 (fault | (state->mmu.last_domain << 4)) & 0xFF;
429 state->mmu.fault_address = address;
430 ARMul_DATAABORT (address);
431 return ARMul_ABORTWORD;
432 }
433 else {
434 ARMul_CLEARABORT;
435 }
436
437 return data;
438
439} 104}
440 105
441/***************************************************************************\ 106ARMword ARMul_LoadHalfWord(ARMul_State * state, ARMword address) {
442* Read Byte (but don't tell anyone!) * 107 state->NumNcycles++;
443\***************************************************************************/ 108 return (u16)Memory::Read16(address);;
444int ARMul_ICE_ReadByte(ARMul_State * state, ARMword address, ARMword *presult)
445{
446 ARMword data;
447 fault_t fault;
448 fault = GetByte (state, address, &data);
449 if (fault) {
450 *presult=-1; fault=ALIGNMENT_FAULT; return fault;
451 }else{
452 *(char *)presult=(unsigned char)(data & 0xff); fault=NO_FAULT; return fault;
453 }
454} 109}
455
456
457ARMword
458ARMul_ReadByte (ARMul_State * state, ARMword address)
459{
460 ARMword data;
461 fault_t fault;
462
463 fault = GetByte (state, address, &data);
464
465 if (fault) {
466 state->mmu.fault_status =
467 (fault | (state->mmu.last_domain << 4)) & 0xFF;
468 state->mmu.fault_address = address;
469 ARMul_DATAABORT (address);
470 return ARMul_ABORTWORD;
471 }
472 else {
473 ARMul_CLEARABORT;
474 }
475
476 return data;
477
478}
479
480/***************************************************************************\
481* Load Byte, (Non Sequential Cycle) *
482\***************************************************************************/
483
484ARMword
485ARMul_LoadByte (ARMul_State * state, ARMword address)
486{
487 state->NumNcycles++;
488
489 return ARMul_ReadByte (state, address);
490}
491
492/***************************************************************************\
493* Write Word (but don't tell anyone!) *
494\***************************************************************************/
495
496void
497ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data)
498{
499 fault_t fault;
500
501#ifdef ABORTS
502 if (address >= LOWABORT && address < HIGHABORT) {
503 ARMul_DATAABORT (address);
504 return;
505 }
506 else {
507 ARMul_CLEARABORT;
508 }
509#endif
510 110
511 fault = PutWord (state, address, data); 111ARMword ARMul_ReadByte(ARMul_State * state, ARMword address) {
512 if (fault) { 112 return (u8)Memory::Read8(address);
513 state->mmu.fault_status =
514 (fault | (state->mmu.last_domain << 4)) & 0xFF;
515 state->mmu.fault_address = address;
516 ARMul_DATAABORT (address);
517 return;
518 }
519 else {
520 ARMul_CLEARABORT;
521 }
522} 113}
523 114
524/***************************************************************************\ 115ARMword ARMul_LoadByte(ARMul_State * state, ARMword address) {
525* Store Word, Sequential Cycle * 116 state->NumNcycles++;
526\***************************************************************************/ 117 return ARMul_ReadByte(state, address);
527
528void
529ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data)
530{
531 state->NumScycles++;
532
533 ARMul_WriteWord (state, address, data);
534} 118}
535 119
536/***************************************************************************\ 120void ARMul_StoreHalfWord(ARMul_State * state, ARMword address, ARMword data) {
537* Store Word, Non Sequential Cycle * 121 state->NumNcycles++;
538\***************************************************************************/ 122 Memory::Write16(address, data);
539
540void
541ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data)
542{
543 state->NumNcycles++;
544
545 ARMul_WriteWord (state, address, data);
546} 123}
547 124
548/***************************************************************************\ 125void ARMul_StoreByte(ARMul_State * state, ARMword address, ARMword data) {
549* Store HalfWord, (Non Sequential Cycle) * 126 state->NumNcycles++;
550\***************************************************************************/ 127 ARMul_WriteByte(state, address, data);
551
552void
553ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data)
554{
555 fault_t fault;
556 state->NumNcycles++;
557 fault = PutHalfWord (state, address, data);
558 if (fault) {
559 state->mmu.fault_status =
560 (fault | (state->mmu.last_domain << 4)) & 0xFF;
561 state->mmu.fault_address = address;
562 ARMul_DATAABORT (address);
563 return;
564 }
565 else {
566 ARMul_CLEARABORT;
567 }
568} 128}
569 129
570//chy 2006-04-15 130ARMword ARMul_SwapWord(ARMul_State * state, ARMword address, ARMword data) {
571int ARMul_ICE_WriteByte (ARMul_State * state, ARMword address, ARMword data) 131 ARMword temp;
572{ 132 state->NumNcycles++;
573 fault_t fault; 133 temp = ARMul_ReadWord(state, address);
574 fault = PutByte (state, address, data); 134 state->NumNcycles++;
575 if (fault) 135 Memory::Write32(address, data);
576 return 1; 136 return temp;
577 else
578 return 0;
579}
580/***************************************************************************\
581* Write Byte (but don't tell anyone!) *
582\***************************************************************************/
583//chy 2003-07-10, add real write byte fun
584void
585ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data)
586{
587 fault_t fault;
588 fault = PutByte (state, address, data);
589 if (fault) {
590 state->mmu.fault_status =
591 (fault | (state->mmu.last_domain << 4)) & 0xFF;
592 state->mmu.fault_address = address;
593 ARMul_DATAABORT (address);
594 return;
595 }
596 else {
597 ARMul_CLEARABORT;
598 }
599} 137}
600 138
601/***************************************************************************\ 139ARMword ARMul_SwapByte(ARMul_State * state, ARMword address, ARMword data) {
602* Store Byte, (Non Sequential Cycle) * 140 ARMword temp;
603\***************************************************************************/ 141 temp = ARMul_LoadByte(state, address);
604 142 Memory::Write8(address, data);
605void 143 return temp;
606ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data)
607{
608 state->NumNcycles++;
609
610#ifdef VALIDATE
611 if (address == TUBE) {
612 if (data == 4)
613 state->Emulate = FALSE;
614 else
615 (void) putc ((char) data, stderr); /* Write Char */
616 return;
617 }
618#endif
619
620 ARMul_WriteByte (state, address, data);
621} 144}
622 145
623/***************************************************************************\ 146void ARMul_WriteWord(ARMul_State * state, ARMword address, ARMword data) {
624* Swap Word, (Two Non Sequential Cycles) * 147 Memory::Write32(address, data);
625\***************************************************************************/
626
627ARMword
628ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data)
629{
630 ARMword temp;
631
632 state->NumNcycles++;
633
634 temp = ARMul_ReadWord (state, address);
635
636 state->NumNcycles++;
637
638 PutWord (state, address, data);
639
640 return temp;
641} 148}
642 149
643/***************************************************************************\ 150void ARMul_WriteByte(ARMul_State * state, ARMword address, ARMword data)
644* Swap Byte, (Two Non Sequential Cycles) *
645\***************************************************************************/
646
647ARMword
648ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data)
649{ 151{
650 ARMword temp; 152 Memory::Write8(address, data);
651
652 temp = ARMul_LoadByte (state, address);
653 ARMul_StoreByte (state, address, data);
654
655 return temp;
656} 153}
657 154
658/***************************************************************************\ 155void ARMul_StoreWordS(ARMul_State * state, ARMword address, ARMword data)
659* Count I Cycles *
660\***************************************************************************/
661
662void
663ARMul_Icycles (ARMul_State * state, unsigned number,
664 ARMword address)
665{ 156{
666 state->NumIcycles += number; 157 state->NumScycles++;
667 ARMul_CLEARABORT; 158 ARMul_WriteWord(state, address, data);
668} 159}
669 160
670/***************************************************************************\ 161void ARMul_StoreWordN(ARMul_State * state, ARMword address, ARMword data)
671* Count C Cycles *
672\***************************************************************************/
673
674void
675ARMul_Ccycles (ARMul_State * state, unsigned number,
676 ARMword address)
677{ 162{
678 state->NumCcycles += number; 163 state->NumNcycles++;
679 ARMul_CLEARABORT; 164 ARMul_WriteWord(state, address, data);
680} 165}
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 @@
1/*
2 arm1176jzf_s_mmu.c - ARM920T Memory Management Unit emulation.
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#include <assert.h>
22#include <string.h>
23#include <stdint.h>
24
25#include "core/mem_map.h"
26
27#include "core/arm/interpreter/skyeye_defs.h"
28
29#include "core/arm/interpreter/armdefs.h"
30//#include "bank_defs.h"
31#if 0
32#define TLB_SIZE 1024 * 1024
33#define ASID 255
34static uint32_t tlb_entry_array[TLB_SIZE][ASID];
35static inline void invalidate_all_tlb(ARMul_State *state){
36 memset(&tlb_entry_array[0], 0xFF, sizeof(uint32_t) * TLB_SIZE * ASID);
37}
38static inline void invalidate_by_mva(ARMul_State *state, ARMword va){
39 memset(&tlb_entry_array[va >> 12][va & 0xFF], 0xFF, sizeof(uint32_t));
40 return;
41}
42static inline void invalidate_by_asid(ARMul_State *state, ARMword asid){
43 int i;
44 for(i = 0; i < TLB_SIZE; i++)
45 memset(&tlb_entry_array[i][asid & 0xFF], 0xFF, sizeof(uint32_t));
46 return;
47}
48
49static uint32_t get_phys_page(ARMul_State* state, ARMword va){
50 uint32_t phys_page = tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF];
51 //printf("In %s, for va=0x%x, page=0x%x\n", __func__, va, phys_page);
52 return phys_page;
53}
54
55static inline void insert_tlb(ARMul_State* state, ARMword va, ARMword pa){
56 //printf("In %s, insert va=0x%x, pa=0x%x\n", __FUNCTION__, va, pa);
57 //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);
58 tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF] = pa >> 12;
59
60 return;
61}
62#endif
63#define BANK0_START 0x50000000
64static void* mem_ptr = NULL;
65
66static int exclusive_detect(ARMul_State* state, ARMword addr){
67 #if 0
68 for(int i = 0; i < 128; i++){
69 if(state->exclusive_tag_array[i] == addr)
70 return 0;
71 }
72 #endif
73 if(state->exclusive_tag_array[0] == addr)
74 return 0;
75 else
76 return -1;
77}
78
79static void add_exclusive_addr(ARMul_State* state, ARMword addr){
80 #if 0
81 for(int i = 0; i < 128; i++){
82 if(state->exclusive_tag_array[i] == 0xffffffff){
83 state->exclusive_tag_array[i] = addr;
84 //printf("In %s, add addr 0x%x\n", __func__, addr);
85 return;
86 }
87 }
88 printf("In %s ,can not monitor the addr, out of array\n", __FUNCTION__);
89 #endif
90 state->exclusive_tag_array[0] = addr;
91 return;
92}
93
94static void remove_exclusive(ARMul_State* state, ARMword addr){
95 #if 0
96 int i;
97 for(i = 0; i < 128; i++){
98 if(state->exclusive_tag_array[i] == addr){
99 state->exclusive_tag_array[i] = 0xffffffff;
100 //printf("In %s, remove addr 0x%x\n", __func__, addr);
101 return;
102 }
103 }
104 #endif
105 state->exclusive_tag_array[0] = 0xFFFFFFFF;
106}
107
108/* This function encodes table 8-2 Interpreting AP bits,
109 returning non-zero if access is allowed. */
110static int
111check_perms (ARMul_State *state, int ap, int read)
112{
113 int s, r, user;
114
115 s = state->mmu.control & CONTROL_SYSTEM;
116 r = state->mmu.control & CONTROL_ROM;
117 /* chy 2006-02-15 , should consider system mode, don't conside 26bit mode */
118// printf("ap is %x, user is %x, s is %x, read is %x\n", ap, user, s, read);
119// printf("mode is %x\n", state->Mode);
120 user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE);
121
122 switch (ap) {
123 case 0:
124 return read && ((s && !user) || r);
125 case 1:
126 return !user;
127 case 2:
128 return read || !user;
129 case 3:
130 return 1;
131 }
132 return 0;
133}
134
135#if 0
136fault_t
137check_access (ARMul_State *state, ARMword virt_addr, tlb_entry_t *tlb,
138 int read)
139{
140 int access;
141
142 state->mmu.last_domain = tlb->domain;
143 access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3;
144 if ((access == 0) || (access == 2)) {
145 /* It's unclear from the documentation whether this
146 should always raise a section domain fault, or if
147 it should be a page domain fault in the case of an
148 L1 that describes a page table. In the ARM710T
149 datasheets, "Figure 8-9: Sequence for checking faults"
150 seems to indicate the former, while "Table 8-4: Priority
151 encoding of fault status" gives a value for FS[3210] in
152 the event of a domain fault for a page. Hmm. */
153 return SECTION_DOMAIN_FAULT;
154 }
155 if (access == 1) {
156 /* client access - check perms */
157 int subpage, ap;
158#if 0
159 switch (tlb->mapping) {
160 /*ks 2004-05-09
161 * only for XScale
162 * Extend Small Page(ESP) Format
163 * 31-12 bits the base addr of ESP
164 * 11-10 bits SBZ
165 * 9-6 bits TEX
166 * 5-4 bits AP
167 * 3 bit C
168 * 2 bit B
169 * 1-0 bits 11
170 * */
171 case TLB_ESMALLPAGE: /* xj */
172 subpage = 0;
173 /* printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); */
174 break;
175
176 case TLB_TINYPAGE:
177 subpage = 0;
178 /* printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); */
179 break;
180
181 case TLB_SMALLPAGE:
182 subpage = (virt_addr >> 10) & 3;
183 break;
184 case TLB_LARGEPAGE:
185 subpage = (virt_addr >> 14) & 3;
186 break;
187 case TLB_SECTION:
188 subpage = 3;
189 break;
190 default:
191 assert (0);
192 subpage = 0; /* cleans a warning */
193 }
194 ap = (tlb->perms >> (subpage * 2 + 4)) & 3;
195 if (!check_perms (state, ap, read)) {
196 if (tlb->mapping == TLB_SECTION) {
197 return SECTION_PERMISSION_FAULT;
198 } else {
199 return SUBPAGE_PERMISSION_FAULT;
200 }
201 }
202#endif
203 } else { /* access == 3 */
204 /* manager access - don't check perms */
205 }
206 return NO_FAULT;
207}
208#endif
209
210#if 0
211fault_t
212mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr)
213#endif
214
215/* ap: AP bits value.
216 * sop: section or page description 0:section 1:page
217 */
218fault_t
219mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr, int *ap, int *sop)
220{
221 {
222 /* walk the translation tables */
223 ARMword l1addr, l1desc;
224 if (state->mmu.translation_table_ctrl && virt_addr << state->mmu.translation_table_ctrl >> (32 - state->mmu.translation_table_ctrl - 1)) {
225 l1addr = state->mmu.translation_table_base1;
226 l1addr = (((l1addr >> 14) << 14) | (virt_addr >> 18)) & ~3;
227 } else {
228 l1addr = state->mmu.translation_table_base0;
229 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;
230 }
231
232 /* l1desc = mem_read_word (state, l1addr); */
233 if (state->space.conf_obj != NULL)
234 state->space.read(state->space.conf_obj, l1addr, &l1desc, 4);
235 else
236 l1desc = Memory::Read32(l1addr); //mem_read_raw(32, l1addr, &l1desc);
237
238 #if 0
239 if (virt_addr == 0xc000d2bc) {
240 printf("mmu_control is %x\n", state->mmu.translation_table_ctrl);
241 printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0);
242 printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1);
243 printf("l1addr is %x l1desc is %x\n", l1addr, l1desc);
244 // exit(-1);
245 }
246 #endif
247 switch (l1desc & 3) {
248 case 0:
249 case 3:
250 /*
251 * according to Figure 3-9 Sequence for checking faults in arm manual,
252 * section translation fault should be returned here.
253 */
254 {
255 return SECTION_TRANSLATION_FAULT;
256 }
257 case 1:
258 /* coarse page table */
259 {
260 ARMword l2addr, l2desc;
261
262
263 l2addr = l1desc & 0xFFFFFC00;
264 l2addr = (l2addr |
265 ((virt_addr & 0x000FF000) >> 10)) &
266 ~3;
267 if(state->space.conf_obj != NULL)
268 state->space.read(state->space.conf_obj, l2addr, &l2desc, 4);
269 else
270 l2desc = Memory::Read32(l2addr); //mem_read_raw(32, l2addr, &l2desc);
271
272 /* chy 2003-09-02 for xscale */
273 *ap = (l2desc >> 4) & 0x3;
274 *sop = 1; /* page */
275
276 switch (l2desc & 3) {
277 case 0:
278 return PAGE_TRANSLATION_FAULT;
279 break;
280 case 1:
281 *phys_addr = (l2desc & 0xFFFF0000) | (virt_addr & 0x0000FFFF);
282 break;
283 case 2:
284 case 3:
285 *phys_addr = (l2desc & 0xFFFFF000) | (virt_addr & 0x00000FFF);
286 break;
287
288 }
289 }
290 break;
291 case 2:
292 /* section */
293
294 *ap = (l1desc >> 10) & 3;
295 *sop = 0; /* section */
296 #if 0
297 if (virt_addr == 0xc000d2bc) {
298 printf("mmu_control is %x\n", state->mmu.translation_table_ctrl);
299 printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0);
300 printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1);
301 printf("l1addr is %x l1desc is %x\n", l1addr, l1desc);
302// printf("l2addr is %x l2desc is %x\n", l2addr, l2desc);
303 printf("ap is %x, sop is %x\n", *ap, *sop);
304 printf("mode is %d\n", state->Mode);
305// exit(-1);
306 }
307 #endif
308
309 if (l1desc & 0x30000)
310 *phys_addr = (l1desc & 0xFF000000) | (virt_addr & 0x00FFFFFF);
311 else
312 *phys_addr = (l1desc & 0xFFF00000) | (virt_addr & 0x000FFFFF);
313 break;
314 }
315 }
316 return NO_FAULT;
317}
318
319
320static fault_t arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va,
321 ARMword data, ARMword datatype);
322static fault_t arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va,
323 ARMword *data, ARMword datatype);
324
325int
326arm1176jzf_s_mmu_init (ARMul_State *state)
327{
328 state->mmu.control = 0x50078;
329 state->mmu.translation_table_base = 0xDEADC0DE;
330 state->mmu.domain_access_control = 0xDEADC0DE;
331 state->mmu.fault_status = 0;
332 state->mmu.fault_address = 0;
333 state->mmu.process_id = 0;
334 state->mmu.context_id = 0;
335 state->mmu.thread_uro_id = 0;
336 //invalidate_all_tlb(state);
337
338 return No_exp;
339}
340
341void
342arm1176jzf_s_mmu_exit (ARMul_State *state)
343{
344}
345
346
347static fault_t
348arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr)
349{
350 fault_t fault;
351 int c; /* cache bit */
352 ARMword pa; /* physical addr */
353 ARMword perm; /* physical addr access permissions */
354 int ap, sop;
355
356 static int debug_count = 0; /* used for debug */
357
358 //DEBUG_LOG(ARM11, "va = %x\n", va);
359
360 va = mmu_pid_va_map (va);
361 if (MMU_Enabled) {
362// printf("MMU enabled.\n");
363// sleep(1);
364 /* align check */
365 if ((va & (WORD_SIZE - 1)) && MMU_Aligned) {
366 DEBUG_LOG(ARM11, "align\n");
367 return ALIGNMENT_FAULT;
368 } else
369 va &= ~(WORD_SIZE - 1);
370
371 /* translate tlb */
372 fault = mmu_translate (state, va, &pa, &ap, &sop);
373 if (fault) {
374 DEBUG_LOG(ARM11, "translate\n");
375 printf("va=0x%x, icounter=%lld, fault=%d\n", va, state->NumInstrs, fault);
376 return fault;
377 }
378
379
380 /* no tlb, only check permission */
381 if (!check_perms(state, ap, 1)) {
382 if (sop == 0) {
383 return SECTION_PERMISSION_FAULT;
384 } else {
385 return SUBPAGE_PERMISSION_FAULT;
386 }
387 }
388
389#if 0
390 /*check access */
391 fault = check_access (state, va, tlb, 1);
392 if (fault) {
393 DEBUG_LOG(ARM11, "check_fault\n");
394 return fault;
395 }
396#endif
397 }
398
399 /*if MMU disabled or C flag is set alloc cache */
400 if (MMU_Disabled) {
401// printf("MMU disabled.\n");
402// sleep(1);
403 pa = va;
404 }
405 if(state->space.conf_obj == NULL)
406 state->space.read(state->space.conf_obj, pa, instr, 4);
407 else
408 *instr = Memory::Read32(pa); //mem_read_raw(32, pa, instr);
409
410 return NO_FAULT;
411}
412
413static fault_t
414arm1176jzf_s_mmu_read_byte (ARMul_State *state, ARMword virt_addr, ARMword *data)
415{
416 /* ARMword temp,offset; */
417 fault_t fault;
418 fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE);
419 return fault;
420}
421
422static fault_t
423arm1176jzf_s_mmu_read_halfword (ARMul_State *state, ARMword virt_addr,
424 ARMword *data)
425{
426 /* ARMword temp,offset; */
427 fault_t fault;
428 fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE);
429 return fault;
430}
431
432static fault_t
433arm1176jzf_s_mmu_read_word (ARMul_State *state, ARMword virt_addr, ARMword *data)
434{
435 return arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);
436}
437
438static fault_t
439arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data,
440 ARMword datatype)
441{
442 fault_t fault;
443 ARMword pa, real_va, temp, offset;
444 ARMword perm; /* physical addr access permissions */
445 int ap, sop;
446
447 //DEBUG_LOG(ARM11, "va = %x\n", va);
448
449 va = mmu_pid_va_map (va);
450 real_va = va;
451 /* if MMU disabled, memory_read */
452 if (MMU_Disabled) {
453// printf("MMU disabled cpu_id:%x addr:%x.\n", state->mmu.process_id, va);
454// sleep(1);
455
456 /* *data = mem_read_word(state, va); */
457 if (datatype == ARM_BYTE_TYPE)
458 /* *data = mem_read_byte (state, va); */
459 if(state->space.conf_obj != NULL)
460 state->space.read(state->space.conf_obj, va, data, 1);
461 else
462 *data = Memory::Read8(va); //mem_read_raw(8, va, data);
463 else if (datatype == ARM_HALFWORD_TYPE)
464 /* *data = mem_read_halfword (state, va); */
465 if(state->space.conf_obj != NULL)
466 state->space.read(state->space.conf_obj, va, data, 2);
467 else
468 *data = Memory::Read16(va); //mem_read_raw(16, va, data);
469 else if (datatype == ARM_WORD_TYPE)
470 /* *data = mem_read_word (state, va); */
471 if(state->space.conf_obj != NULL)
472 state->space.read(state->space.conf_obj, va, data, 4);
473 else
474 *data = Memory::Read32(va); //mem_read_raw(32, va, data);
475 else {
476 ERROR_LOG(ARM11, "SKYEYE:1 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype);
477 }
478
479 return NO_FAULT;
480 }
481// printf("MMU enabled.\n");
482// sleep(1);
483
484 /* align check */
485 if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
486 ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
487 DEBUG_LOG(ARM11, "align\n");
488 return ALIGNMENT_FAULT;
489 }
490
491 /* va &= ~(WORD_SIZE - 1); */
492 #if 0
493 uint32_t page_base;
494 page_base = get_phys_page(state, va);
495 if((page_base & 0xFFF) == 0){
496 pa = (page_base << 12) | (va & 0xFFF);
497 goto skip_translation;
498 }
499 #endif
500 /*translate va to tlb */
501#if 0
502 fault = mmu_translate (state, va, ARM920T_D_TLB (), &tlb);
503#endif
504 fault = mmu_translate (state, va, &pa, &ap, &sop);
505#if 0
506 if(va ==0xbebb1774 || state->Reg[15] == 0x400ff594){
507 //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]);
508 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);
509 int i;
510 for(i = 0; i < 16; i++)
511 printf("Reg[%d]=0x%x\t", i, state->Reg[i]);
512 printf("\n");
513 }
514#endif
515 if (fault) {
516 DEBUG_LOG(ARM11, "translate\n");
517 //printf("mmu read fault at %x\n", va);
518 //printf("fault is %d\n", fault);
519 return fault;
520 }
521// printf("va is %x pa is %x\n", va, pa);
522
523 /* no tlb, only check permission */
524 if (!check_perms(state, ap, 1)) {
525 if (sop == 0) {
526 return SECTION_PERMISSION_FAULT;
527 } else {
528 return SUBPAGE_PERMISSION_FAULT;
529 }
530 }
531#if 0
532 /*check access permission */
533 fault = check_access (state, va, tlb, 1);
534 if (fault)
535 return fault;
536#endif
537
538 //insert_tlb(state, va, pa);
539skip_translation:
540 /* *data = mem_read_word(state, pa); */
541 if (datatype == ARM_BYTE_TYPE) {
542 /* *data = mem_read_byte (state, pa | (real_va & 3)); */
543 if(state->space.conf_obj != NULL)
544 state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 1);
545 else
546 *data = Memory::Read8(pa | (real_va & 3)); //mem_read_raw(8, pa | (real_va & 3), data);
547 /* mem_read_raw(32, pa | (real_va & 3), data); */
548 } else if (datatype == ARM_HALFWORD_TYPE) {
549 /* *data = mem_read_halfword (state, pa | (real_va & 2)); */
550 if(state->space.conf_obj != NULL)
551 state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 2);
552 else
553 *data = Memory::Read16(pa | (real_va & 3)); //mem_read_raw(16, pa | (real_va & 3), data);
554 /* mem_read_raw(32, pa | (real_va & 2), data); */
555 } else if (datatype == ARM_WORD_TYPE)
556 /* *data = mem_read_word (state, pa); */
557 if(state->space.conf_obj != NULL)
558 state->space.read(state->space.conf_obj, pa , data, 4);
559 else
560 *data = Memory::Read32(pa); //mem_read_raw(32, pa, data);
561 else {
562 ERROR_LOG(ARM11, "SKYEYE:2 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype);
563 }
564 if(0 && (va == 0x2869c)){
565 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);
566 }
567
568 /* ldrex or ldrexb */
569 if(((state->CurrInstr & 0x0FF000F0) == 0x01900090) ||
570 ((state->CurrInstr & 0x0FF000F0) == 0x01d00090)){
571 int rn = (state->CurrInstr & 0xF0000) >> 16;
572 if(state->Reg[rn] == va){
573 add_exclusive_addr(state, pa | (real_va & 3));
574 state->exclusive_access_state = 1;
575 }
576 }
577#if 0
578 if (state->pc == 0xc011a868) {
579 printf("pa is %x value is %x size is %x\n", pa, data, datatype);
580 printf("icounter is %lld\n", state->NumInstrs);
581// exit(-1);
582 }
583#endif
584
585 return NO_FAULT;
586}
587
588
589static fault_t
590arm1176jzf_s_mmu_write_byte (ARMul_State *state, ARMword virt_addr, ARMword data)
591{
592 return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);
593}
594
595static fault_t
596arm1176jzf_s_mmu_write_halfword (ARMul_State *state, ARMword virt_addr,
597 ARMword data)
598{
599 return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);
600}
601
602static fault_t
603arm1176jzf_s_mmu_write_word (ARMul_State *state, ARMword virt_addr, ARMword data)
604{
605 return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);
606}
607
608
609
610static fault_t
611arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data,
612 ARMword datatype)
613{
614 int b;
615 ARMword pa, real_va;
616 ARMword perm; /* physical addr access permissions */
617 fault_t fault;
618 int ap, sop;
619
620#if 0
621 /8 for sky_printk debugger.*/
622 if (va == 0xffffffff) {
623 putchar((char)data);
624 return 0;
625 }
626 if (va == 0xBfffffff) {
627 putchar((char)data);
628 return 0;
629 }
630#endif
631
632 //DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data);
633 va = mmu_pid_va_map (va);
634 real_va = va;
635
636 if (MMU_Disabled) {
637 /* mem_write_word(state, va, data); */
638 if (datatype == ARM_BYTE_TYPE)
639 /* mem_write_byte (state, va, data); */
640 if(state->space.conf_obj != NULL)
641 state->space.write(state->space.conf_obj, va, &data, 1);
642 else
643 Memory::Write8(va, data);
644 else if (datatype == ARM_HALFWORD_TYPE)
645 /* mem_write_halfword (state, va, data); */
646 if(state->space.conf_obj != NULL)
647 state->space.write(state->space.conf_obj, va, &data, 2);
648 else
649 Memory::Write16(va, data);
650 else if (datatype == ARM_WORD_TYPE)
651 /* mem_write_word (state, va, data); */
652 if(state->space.conf_obj != NULL)
653 state->space.write(state->space.conf_obj, va, &data, 4);
654 else
655 Memory::Write32(va, data);
656 else {
657 ERROR_LOG (ARM11, "SKYEYE:1 arm1176jzf_s_mmu_write error: unknown data type %d\n", datatype);
658 }
659 goto finished_write;
660 //return 0;
661 }
662 /*align check */
663 /* if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ */
664 if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
665 ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
666 DEBUG_LOG(ARM11, "align\n");
667 return ALIGNMENT_FAULT;
668 }
669 va &= ~(WORD_SIZE - 1);
670 #if 0
671 uint32_t page_base;
672 page_base = get_phys_page(state, va);
673 if((page_base & 0xFFF) == 0){
674 pa = (page_base << 12) | (va & 0xFFF);
675 goto skip_translation;
676 }
677 #endif
678 /*tlb translate */
679 fault = mmu_translate (state, va, &pa, &ap, &sop);
680#if 0
681 if(va ==0xbebb1774 || state->Reg[15] == 0x40102334){
682 //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]);
683 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);
684 int i;
685 for(i = 0; i < 16; i++)
686 printf("Reg[%d]=0x%x\t", i, state->Reg[i]);
687 printf("\n");
688 }
689#endif
690 if (fault) {
691 DEBUG_LOG(ARM11, "translate\n");
692 //printf("mmu write fault at %x\n", va);
693 return fault;
694 }
695// printf("va is %x pa is %x\n", va, pa);
696
697 /* no tlb, only check permission */
698 if (!check_perms(state, ap, 0)) {
699 if (sop == 0) {
700 return SECTION_PERMISSION_FAULT;
701 } else {
702 return SUBPAGE_PERMISSION_FAULT;
703 }
704 }
705
706#if 0
707 /* tlb check access */
708 fault = check_access (state, va, tlb, 0);
709 if (fault) {
710 DEBUG_LOG(ARM11, "check_access\n");
711 return fault;
712 }
713#endif
714#if 0
715 if (pa <= 0x502860ff && (pa + 1 << datatype) > 0x502860ff) {
716 printf("pa is %x value is %x size is %x\n", pa, data, datatype);
717 }
718#endif
719#if 0
720 if (state->pc == 0xc011a878) {
721 printf("write pa is %x value is %x size is %x\n", pa, data, datatype);
722 printf("icounter is %lld\n", state->NumInstrs);
723 exit(-1);
724 }
725#endif
726 //insert_tlb(state, va, pa);
727skip_translation:
728 /* strex */
729 if(((state->CurrInstr & 0x0FF000F0) == 0x01800090) ||
730 ((state->CurrInstr & 0x0FF000F0) == 0x01c00090)){
731 /* failed , the address is monitord now. */
732 int dest_reg = (state->CurrInstr & 0xF000) >> 12;
733 if((exclusive_detect(state, pa | (real_va & 3)) == 0) && (state->exclusive_access_state == 1)){
734 remove_exclusive(state, pa | (real_va & 3));
735 state->Reg[dest_reg] = 0;
736 state->exclusive_access_state = 0;
737 }
738 else{
739 state->Reg[dest_reg] = 1;
740 //printf("In %s, try to strex a monitored address 0x%x\n", __FUNCTION__, pa);
741 return NO_FAULT;
742 }
743 }
744
745 if (datatype == ARM_BYTE_TYPE) {
746 /* mem_write_byte (state,
747 (pa | (real_va & 3)),
748 data);
749 */
750 if(state->space.conf_obj != NULL)
751 state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 1);
752 else
753 Memory::Write8((pa | (real_va & 3)), data);
754
755 } else if (datatype == ARM_HALFWORD_TYPE)
756 /* mem_write_halfword (state,
757 (pa |
758 (real_va & 2)),
759 data);
760 */
761 if(state->space.conf_obj != NULL)
762 state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 2);
763 else
764 Memory::Write16((pa | (real_va & 3)), data);
765 else if (datatype == ARM_WORD_TYPE)
766 /* mem_write_word (state, pa, data); */
767 if(state->space.conf_obj != NULL)
768 state->space.write(state->space.conf_obj, pa, &data, 4);
769 else
770 Memory::Write32(pa, data);
771#if 0
772 if (state->NumInstrs > 236403) {
773 printf("write memory\n");
774 printf("pa is %x value is %x size is %x\n", pa, data, datatype);
775 printf("icounter is %lld\n", state->NumInstrs);
776 }
777#endif
778finished_write:
779#if DIFF_WRITE
780 if(state->icounter > state->debug_icounter){
781 if(state->CurrWrite >= 17 ){
782 printf("Wrong write array, 0x%x", state->CurrWrite);
783 exit(-1);
784 }
785 uint32 record_data = data;
786 if(datatype == ARM_BYTE_TYPE)
787 record_data &= 0xFF;
788 if(datatype == ARM_HALFWORD_TYPE)
789 record_data &= 0xFFFF;
790
791 state->WriteAddr[state->CurrWrite] = pa | (real_va & 3);
792 state->WriteData[state->CurrWrite] = record_data;
793 state->WritePc[state->CurrWrite] = state->Reg[15];
794 state->CurrWrite++;
795 //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);
796 }
797#endif
798
799 return NO_FAULT;
800}
801
802ARMword
803arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value)
804{
805 int creg = BITS (16, 19) & 0xf;
806 int OPC_1 = BITS (21, 23) & 0x7;
807 int OPC_2 = BITS (5, 7) & 0x7;
808 ARMword data;
809
810 switch (creg) {
811 case MMU_ID:
812 if (OPC_2 == 0) {
813 data = state->cpu->cpu_val;
814 } else if (OPC_2 == 1) {
815 /* Cache type:
816 * 000 0110 1 000 101 110 0 10 000 101 110 0 10
817 * */
818 data = 0x0D172172;
819 }
820 break;
821 case MMU_CONTROL:
822 /*
823 * 6:3 read as 1
824 * 10 read as 0
825 * 18,16 read as 1
826 * */
827 data = (state->mmu.control | 0x50078) & 0xFFFFFBFF;
828 break;
829 case MMU_TRANSLATION_TABLE_BASE:
830#if 0
831 data = state->mmu.translation_table_base;
832#endif
833 switch (OPC_2) {
834 case 0:
835 data = state->mmu.translation_table_base0;
836 break;
837 case 1:
838 data = state->mmu.translation_table_base1;
839 break;
840 case 2:
841 data = state->mmu.translation_table_ctrl;
842 break;
843 default:
844 printf ("mmu_mrc read UNKNOWN - p15 c2 opcode2 %d\n", OPC_2);
845 break;
846 }
847 break;
848 case MMU_DOMAIN_ACCESS_CONTROL:
849 data = state->mmu.domain_access_control;
850 break;
851 case MMU_FAULT_STATUS:
852 /* OPC_2 = 0: data FSR value
853 * */
854 if (OPC_2 == 0)
855 data = state->mmu.fault_status;
856 if (OPC_2 == 1)
857 data = state->mmu.fault_statusi;
858 break;
859 case MMU_FAULT_ADDRESS:
860 data = state->mmu.fault_address;
861 break;
862 case MMU_PID:
863 //data = state->mmu.process_id;
864 if(OPC_2 == 0)
865 data = state->mmu.process_id;
866 else if(OPC_2 == 1)
867 data = state->mmu.context_id;
868 else if(OPC_2 == 3){
869 data = state->mmu.thread_uro_id;
870 }
871 else{
872 printf ("mmu_mcr read UNKNOWN - reg %d\n", creg);
873 }
874 //printf("SKYEYE In %s, read pid 0x%x, OPC_2 %d, instr=0x%x\n", __FUNCTION__, data, OPC_2, instr);
875 //exit(-1);
876 break;
877 default:
878 printf ("mmu_mrc read UNKNOWN - reg %d\n", creg);
879 data = 0;
880 break;
881 }
882/* printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); */
883 *value = data;
884 return data;
885}
886
887
888static ARMword
889arm1176jzf_s_mmu_mcr (ARMul_State *state, ARMword instr, ARMword value)
890{
891 int creg = BITS (16, 19) & 0xf;
892 int CRm = BITS (0, 3) & 0xf;
893 int OPC_1 = BITS (21, 23) & 0x7;
894 int OPC_2 = BITS (5, 7) & 0x7;
895 if (!strncmp (state->cpu->cpu_arch_name, "armv6", 5)) {
896 switch (creg) {
897 case MMU_CONTROL:
898 /*
899 * 6:3 read as 1
900 * 10 read as 0
901 * 18,16 read as 1
902 * */
903 if(OPC_2 == 0)
904 state->mmu.control = (value | 0x50078) & 0xFFFFFBFF;
905 else if(OPC_2 == 1)
906 state->mmu.auxiliary_control = value;
907 else if(OPC_2 == 2)
908 state->mmu.coprocessor_access_control = value;
909 else
910 fprintf(stderr, "In %s, wrong OPC_2 %d\n", __FUNCTION__, OPC_2);
911 break;
912 case MMU_TRANSLATION_TABLE_BASE:
913 switch (OPC_2) {
914 /* int i; */
915 case 0:
916#if 0
917 /* TTBR0 */
918 if (state->mmu.translation_table_ctrl & 0x7) {
919 for (i = 0; i <= state->mmu.translation_table_ctrl; i++)
920 state->mmu.translation_table_base0 &= ~(1 << (5 + i));
921 }
922#endif
923 state->mmu.translation_table_base0 = (value);
924 break;
925 case 1:
926#if 0
927 /* TTBR1 */
928 if (state->mmu.translation_table_ctrl & 0x7) {
929 for (i = 0; i <= state->mmu.translation_table_ctrl; i++)
930 state->mmu.translation_table_base1 &= 1 << (5 + i);
931 }
932#endif
933 state->mmu.translation_table_base1 = (value);
934 break;
935 case 2:
936 /* TTBC */
937 state->mmu.translation_table_ctrl = value & 0x7;
938 break;
939 default:
940 printf ("mmu_mcr wrote UNKNOWN - cp15 c2 opcode2 %d\n", OPC_2);
941 break;
942 }
943 //printf("SKYEYE In %s, write TLB_BASE 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr);
944 //invalidate_all_tlb(state);
945 break;
946 case MMU_DOMAIN_ACCESS_CONTROL:
947 /* printf("mmu_mcr wrote DACR "); */
948 state->mmu.domain_access_control = value;
949 break;
950
951 case MMU_FAULT_STATUS:
952 if (OPC_2 == 0)
953 state->mmu.fault_status = value & 0xFF;
954 if (OPC_2 == 1) {
955 printf("set fault status instr\n");
956 }
957 break;
958 case MMU_FAULT_ADDRESS:
959 state->mmu.fault_address = value;
960 break;
961
962 case MMU_CACHE_OPS:
963 break;
964 case MMU_TLB_OPS:
965 {
966 switch(CRm){
967 case 5: /* ITLB */
968 {
969 switch(OPC_2){
970 case 0: /* invalidate all */
971 //invalidate_all_tlb(state);
972 break;
973 case 1: /* invalidate by MVA */
974 //invalidate_by_mva(state, value);
975 break;
976 case 2: /* invalidate by asid */
977 //invalidate_by_asid(state, value);
978 break;
979 default:
980 printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
981 break;
982 }
983 break;
984 }
985 case 6: /* DTLB */
986 {
987 switch(OPC_2){
988 case 0: /* invalidate all */
989 //invalidate_all_tlb(state);
990 break;
991 case 1: /* invalidate by MVA */
992 //invalidate_by_mva(state, value);
993 break;
994 case 2: /* invalidate by asid */
995 //invalidate_by_asid(state, value);
996 break;
997 default:
998 printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
999 break;
1000 }
1001 break;
1002 }
1003 case 7: /* Unified TLB */
1004 {
1005 switch(OPC_2){
1006 case 0: /* invalidate all */
1007 //invalidate_all_tlb(state);
1008 break;
1009 case 1: /* invalidate by MVA */
1010 //invalidate_by_mva(state, value);
1011 break;
1012 case 2: /* invalidate by asid */
1013 //invalidate_by_asid(state, value);
1014 break;
1015 default:
1016 printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
1017 break;
1018 }
1019 break;
1020 }
1021
1022 default:
1023 printf ("mmu_mcr wrote UNKNOWN - reg %d, CRm=%d\n", creg, CRm);
1024 break;
1025 }
1026 //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);
1027 }
1028 break;
1029 case MMU_CACHE_LOCKDOWN:
1030 /*
1031 * FIXME: cache lock down*/
1032 break;
1033 case MMU_TLB_LOCKDOWN:
1034 printf("SKYEYE In %s, write TLB_LOCKDOWN 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr);
1035 /* FIXME:tlb lock down */
1036 break;
1037 case MMU_PID:
1038 //printf("SKYEYE In %s, write pid 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr);
1039 //state->mmu.process_id = value;
1040 /*0:24 should be zero. */
1041 //state->mmu.process_id = value & 0xfe000000;
1042 if(OPC_2 == 0)
1043 state->mmu.process_id = value;
1044 else if(OPC_2 == 1)
1045 state->mmu.context_id = value;
1046 else if(OPC_2 == 3){
1047 state->mmu.thread_uro_id = value;
1048 }
1049 else{
1050 printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
1051 }
1052 break;
1053
1054 default:
1055 printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
1056 break;
1057 }
1058 }
1059
1060 return No_exp;
1061}
1062
1063///* teawater add for arm2x86 2005.06.19------------------------------------------- */
1064//static int
1065//arm1176jzf_s_mmu_v2p_dbct (ARMul_State *state, ARMword virt_addr,
1066// ARMword *phys_addr)
1067//{
1068// fault_t fault;
1069// int ap, sop;
1070//
1071// ARMword perm; /* physical addr access permissions */
1072// virt_addr = mmu_pid_va_map (virt_addr);
1073// if (MMU_Enabled) {
1074//
1075// /*align check */
1076// if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) {
1077// DEBUG_LOG(ARM11, "align\n");
1078// return ALIGNMENT_FAULT;
1079// } else
1080// virt_addr &= ~(WORD_SIZE - 1);
1081//
1082// /*translate tlb */
1083// fault = mmu_translate (state, virt_addr, phys_addr, &ap, &sop);
1084// if (fault) {
1085// DEBUG_LOG(ARM11, "translate\n");
1086// return fault;
1087// }
1088//
1089// /* permission check */
1090// if (!check_perms(state, ap, 1)) {
1091// if (sop == 0) {
1092// return SECTION_PERMISSION_FAULT;
1093// } else {
1094// return SUBPAGE_PERMISSION_FAULT;
1095// }
1096// }
1097//#if 0
1098// /*check access */
1099// fault = check_access (state, virt_addr, tlb, 1);
1100// if (fault) {
1101// DEBUG_LOG(ARM11, "check_fault\n");
1102// return fault;
1103// }
1104//#endif
1105// }
1106//
1107// if (MMU_Disabled) {
1108// *phys_addr = virt_addr;
1109// }
1110//
1111// return 0;
1112//}
1113
1114/* AJ2D-------------------------------------------------------------------------- */
1115
1116/*arm1176jzf-s mmu_ops_t*/
1117mmu_ops_t arm1176jzf_s_mmu_ops = {
1118 arm1176jzf_s_mmu_init,
1119 arm1176jzf_s_mmu_exit,
1120 arm1176jzf_s_mmu_read_byte,
1121 arm1176jzf_s_mmu_write_byte,
1122 arm1176jzf_s_mmu_read_halfword,
1123 arm1176jzf_s_mmu_write_halfword,
1124 arm1176jzf_s_mmu_read_word,
1125 arm1176jzf_s_mmu_write_word,
1126 arm1176jzf_s_mmu_load_instr,
1127 arm1176jzf_s_mmu_mcr,
1128 arm1176jzf_s_mmu_mrc
1129/* teawater add for arm2x86 2005.06.19------------------------------------------- */
1130/* arm1176jzf_s_mmu_v2p_dbct, */
1131/* AJ2D-------------------------------------------------------------------------- */
1132};
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 @@
1/*
2 arm1176JZF-S_mmu.h - ARM1176JZF-S Memory Management Unit emulation.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*/
18
19#ifndef _ARM1176JZF_S_MMU_H_
20#define _ARM1176JZF_S_MMU_H_
21
22#if 0
23typedef struct arm1176jzf-s_mmu_s
24{
25 tlb_t i_tlb;
26 cache_t i_cache;
27
28 tlb_t d_tlb;
29 cache_t d_cache;
30 wb_t wb_t;
31} arm1176jzf-s_mmu_t;
32#endif
33extern mmu_ops_t arm1176jzf_s_mmu_ops;
34
35ARMword
36arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value);
37#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 @@
1#include "core/arm/interpreter/armdefs.h"
2
3/* mmu cache init
4 *
5 * @cache_t :cache_t to init
6 * @width :cache line width in byte
7 * @way :way of each cache set
8 * @set :cache set num
9 *
10 * $ -1: error
11 * 0: sucess
12 */
13int
14mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode)
15{
16 int i, j;
17 cache_set_t *sets;
18 cache_line_t *lines;
19
20 /*alloc cache set */
21 sets = NULL;
22 lines = NULL;
23 //fprintf(stderr, "mmu_cache_init: mallloc beg size %d,sets 0x%x\n", sizeof(cache_set_t) * set,sets);
24 //exit(-1);
25 sets = (cache_set_t *) malloc (sizeof (cache_set_t) * set);
26 if (sets == NULL) {
27 ERROR_LOG(ARM11, "set malloc size %d\n", sizeof (cache_set_t) * set);
28 goto sets_error;
29 }
30 //fprintf(stderr, "mmu_cache_init: mallloc end sets 0x%x\n", sets);
31 cache_t->sets = sets;
32
33 /*init cache set */
34 for (i = 0; i < set; i++) {
35 /*alloc cache line */
36 lines = (cache_line_t *) malloc (sizeof (cache_line_t) * way);
37 if (lines == NULL) {
38 ERROR_LOG(ARM11, "line malloc size %d\n",
39 sizeof (cache_line_t) * way);
40 goto lines_error;
41 }
42 /*init cache line */
43 for (j = 0; j < way; j++) {
44 lines[j].tag = 0; //invalid
45 lines[j].data = (ARMword *) malloc (width);
46 if (lines[j].data == NULL) {
47 ERROR_LOG(ARM11, "data alloc size %d\n", width);
48 goto data_error;
49 }
50 }
51
52 sets[i].lines = lines;
53 sets[i].cycle = 0;
54
55 }
56 cache_t->width = width;
57 cache_t->set = set;
58 cache_t->way = way;
59 cache_t->w_mode = w_mode;
60 return 0;
61
62 data_error:
63 /*free data */
64 while (j-- > 0)
65 free (lines[j].data);
66 /*free data error line */
67 free (lines);
68 lines_error:
69 /*free lines already alloced */
70 while (i-- > 0) {
71 for (j = 0; j < way; j++)
72 free (sets[i].lines[j].data);
73 free (sets[i].lines);
74 }
75 /*free sets */
76 free (sets);
77 sets_error:
78 return -1;
79};
80
81/* free a cache_t's inner data, the ptr self is not freed,
82 * when needed do like below:
83 * mmu_cache_exit(cache);
84 * free(cache_t);
85 *
86 * @cache_t : the cache_t to free
87 */
88
89void
90mmu_cache_exit (cache_s * cache_t)
91{
92 int i, j;
93 cache_set_t *sets, *set;
94 cache_line_t *lines, *line;
95
96 /*free all set */
97 sets = cache_t->sets;
98 for (set = sets, i = 0; i < cache_t->set; i++, set++) {
99 /*free all line */
100 lines = set->lines;
101 for (line = lines, j = 0; j < cache_t->way; j++, line++)
102 free (line->data);
103 free (lines);
104 }
105 free (sets);
106}
107
108/* mmu cache search
109 *
110 * @state :ARMul_State
111 * @cache_t :cache_t to search
112 * @va :virtual address
113 *
114 * $ NULL: no cache match
115 * cache :cache matched
116 */
117cache_line_t *
118mmu_cache_search (ARMul_State * state, cache_s * cache_t, ARMword va)
119{
120 int i;
121 int set = va_cache_set (va, cache_t);
122 ARMword tag = va_cache_align (va, cache_t);
123 cache_line_t *cache;
124
125 cache_set_t *cache_set = cache_t->sets + set;
126 for (i = 0, cache = cache_set->lines; i < cache_t->way; i++, cache++) {
127 if ((cache->tag & TAG_VALID_FLAG)
128 && (tag == va_cache_align (cache->tag, cache_t)))
129 return cache;
130 }
131 return NULL;
132}
133
134/* mmu cache search by set/index
135 *
136 * @state :ARMul_State
137 * @cache_t :cache_t to search
138 * @index :set/index value.
139 *
140 * $ NULL: no cache match
141 * cache :cache matched
142 */
143cache_line_t *
144mmu_cache_search_by_index (ARMul_State * state, cache_s * cache_t,
145 ARMword index)
146{
147 int way = cache_t->way;
148 int set_v = index_cache_set (index, cache_t);
149 int i = 0, index_v = 0;
150 cache_set_t *set;
151
152 while ((way >>= 1) >= 1)
153 i++;
154 index_v = index >> (32 - i);
155 set = cache_t->sets + set_v;
156
157 return set->lines + index_v;
158}
159
160
161/* mmu cache alloc
162 *
163 * @state :ARMul_State
164 * @cache_t :cache_t to alloc from
165 * @va :virtual address that require cache alloc, need not cache aligned
166 * @pa :physical address of va
167 *
168 * $ cache_alloced, always alloc OK
169 */
170cache_line_t *
171mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, ARMword va,
172 ARMword pa)
173{
174 cache_line_t *cache;
175 cache_set_t *set;
176 int i;
177
178 va = va_cache_align (va, cache_t);
179 pa = va_cache_align (pa, cache_t);
180
181 set = &cache_t->sets[va_cache_set (va, cache_t)];
182
183 /*robin-round */
184 cache = &set->lines[set->cycle++];
185 if (set->cycle == cache_t->way)
186 set->cycle = 0;
187
188 if (cache_t->w_mode == CACHE_WRITE_BACK) {
189 ARMword t;
190
191 /*if cache valid, try to write back */
192 if (cache->tag & TAG_VALID_FLAG) {
193 mmu_cache_write_back (state, cache_t, cache);
194 }
195 /*read in cache_line */
196 t = pa;
197 for (i = 0; i < (cache_t->width >> WORD_SHT);
198 i++, t += WORD_SIZE) {
199 //cache->data[i] = mem_read_word (state, t);
200 bus_read(32, t, &cache->data[i]);
201 }
202 }
203 /*store tag and pa */
204 cache->tag = va | TAG_VALID_FLAG;
205 cache->pa = pa;
206
207 return cache;
208};
209
210/* mmu_cache_write_back write cache data to memory
211 * @state
212 * @cache_t :cache_t of the cache line
213 * @cache : cache line
214 */
215void
216mmu_cache_write_back (ARMul_State * state, cache_s * cache_t,
217 cache_line_t * cache)
218{
219 ARMword pa = cache->pa;
220 int nw = cache_t->width >> WORD_SHT;
221 ARMword *data = cache->data;
222 int i;
223 int t0, t1, t2;
224
225 if ((cache->tag & 1) == 0)
226 return;
227
228 switch (cache->
229 tag & ~1 & (TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY)) {
230 case 0:
231 return;
232 case TAG_FIRST_HALF_DIRTY:
233 nw /= 2;
234 break;
235 case TAG_LAST_HALF_DIRTY:
236 nw /= 2;
237 pa += nw << WORD_SHT;
238 data += nw;
239 break;
240 case TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY:
241 break;
242 }
243 for (i = 0; i < nw; i++, data++, pa += WORD_SIZE)
244 //mem_write_word (state, pa, *data);
245 bus_write(32, pa, *data);
246
247 cache->tag &= ~(TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY);
248};
249
250
251/* mmu_cache_clean: clean a cache of va in cache_t
252 *
253 * @state :ARMul_State
254 * @cache_t :cache_t to clean
255 * @va :virtaul address
256 */
257void
258mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va)
259{
260 cache_line_t *cache;
261
262 cache = mmu_cache_search (state, cache_t, va);
263 if (cache)
264 mmu_cache_write_back (state, cache_t, cache);
265}
266
267/* mmu_cache_clean_by_index: clean a cache by set/index format value
268 *
269 * @state :ARMul_State
270 * @cache_t :cache_t to clean
271 * @va :set/index format value
272 */
273void
274mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t,
275 ARMword index)
276{
277 cache_line_t *cache;
278
279 cache = mmu_cache_search_by_index (state, cache_t, index);
280 if (cache)
281 mmu_cache_write_back (state, cache_t, cache);
282}
283
284/* mmu_cache_invalidate : invalidate a cache of va
285 *
286 * @state :ARMul_State
287 * @cache_t :cache_t to invalid
288 * @va :virt_addr to invalid
289 */
290void
291mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va)
292{
293 cache_line_t *cache;
294
295 cache = mmu_cache_search (state, cache_t, va);
296 if (cache) {
297 mmu_cache_write_back (state, cache_t, cache);
298 cache->tag = 0;
299 }
300}
301
302/* mmu_cache_invalidate_by_index : invalidate a cache by index format
303 *
304 * @state :ARMul_State
305 * @cache_t :cache_t to invalid
306 * @index :set/index data
307 */
308void
309mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t,
310 ARMword index)
311{
312 cache_line_t *cache;
313
314 cache = mmu_cache_search_by_index (state, cache_t, index);
315 if (cache) {
316 mmu_cache_write_back (state, cache_t, cache);
317 cache->tag = 0;
318 }
319}
320
321/* mmu_cache_invalidate_all
322 *
323 * @state:
324 * @cache_t
325 * */
326void
327mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t)
328{
329 int i, j;
330 cache_set_t *set;
331 cache_line_t *cache;
332
333 set = cache_t->sets;
334 for (i = 0; i < cache_t->set; i++, set++) {
335 cache = set->lines;
336 for (j = 0; j < cache_t->way; j++, cache++) {
337 mmu_cache_write_back (state, cache_t, cache);
338 cache->tag = 0;
339 }
340 }
341};
342
343void
344mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa)
345{
346 ARMword set, way;
347 cache_line_t *cache;
348 pa = (pa / cache_t->width);
349 way = pa & (cache_t->way - 1);
350 set = (pa / cache_t->way) & (cache_t->set - 1);
351 cache = &cache_t->sets[set].lines[way];
352
353 mmu_cache_write_back (state, cache_t, cache);
354 cache->tag = 0;
355}
356
357cache_line_t* mmu_cache_dirty_cache(ARMul_State *state,cache_s *cache){
358 int i;
359 int j;
360 cache_line_t *cache_line = NULL;
361 cache_set_t *cache_set = cache->sets;
362 int sets = cache->set;
363 for (i = 0; i < sets; i++){
364 for(j = 0,cache_line = &cache_set[i].lines[0]; j < cache->way; j++,cache_line++){
365 if((cache_line->tag & TAG_FIRST_HALF_DIRTY) || (cache_line->tag & TAG_LAST_HALF_DIRTY))
366 return cache_line;
367 }
368 }
369 return NULL;
370}
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 @@
1#ifndef _MMU_CACHE_H_
2#define _MMU_CACHE_H_
3
4typedef struct cache_line_t
5{
6 ARMword tag; /* cache line align address |
7 bit2: last half dirty
8 bit1: first half dirty
9 bit0: cache valid flag
10 */
11 ARMword pa; /*physical address */
12 ARMword *data; /*array of cached data */
13} cache_line_t;
14#define TAG_VALID_FLAG 0x00000001
15#define TAG_FIRST_HALF_DIRTY 0x00000002
16#define TAG_LAST_HALF_DIRTY 0x00000004
17
18/*cache set association*/
19typedef struct cache_set_s
20{
21 cache_line_t *lines;
22 int cycle;
23} cache_set_t;
24
25enum
26{
27 CACHE_WRITE_BACK,
28 CACHE_WRITE_THROUGH,
29};
30
31typedef struct cache_s
32{
33 int width; /*bytes in a line */
34 int way; /*way of set asscociate */
35 int set; /*num of set */
36 int w_mode; /*write back or write through */
37 //int a_mode; /*alloc mode: random or round-bin*/
38 cache_set_t *sets;
39 /**/} cache_s;
40
41typedef struct cache_desc_s
42{
43 int width;
44 int way;
45 int set;
46 int w_mode;
47// int a_mode;
48} cache_desc_t;
49
50
51/*virtual address to cache set index*/
52#define va_cache_set(va, cache_t) \
53 (((va) / (cache_t)->width) & ((cache_t)->set - 1))
54/*virtual address to cahce line aligned*/
55#define va_cache_align(va, cache_t) \
56 ((va) & ~((cache_t)->width - 1))
57/*virtaul address to cache line word index*/
58#define va_cache_index(va, cache_t) \
59 (((va) & ((cache_t)->width - 1)) >> WORD_SHT)
60
61/*see Page 558 in arm manual*/
62/*set/index format value to cache set value*/
63#define index_cache_set(index, cache_t) \
64 (((index) / (cache_t)->width) & ((cache_t)->set - 1))
65
66/*************************cache********************/
67/* mmu cache init
68 *
69 * @cache_t :cache_t to init
70 * @width :cache line width in byte
71 * @way :way of each cache set
72 * @set :cache set num
73 * @w_mode :cache w_mode
74 *
75 * $ -1: error
76 * 0: sucess
77 */
78int
79mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode);
80
81/* free a cache_t's inner data, the ptr self is not freed,
82 * when needed do like below:
83 * mmu_cache_exit(cache);
84 * free(cache_t);
85 *
86 * @cache_t : the cache_t to free
87 */
88void mmu_cache_exit (cache_s * cache_t);
89
90/* mmu cache search
91 *
92 * @state :ARMul_State
93 * @cache_t :cache_t to search
94 * @va :virtual address
95 *
96 * $ NULL: no cache match
97 * cache :cache matched
98 * */
99cache_line_t *mmu_cache_search (ARMul_State * state, cache_s * cache_t,
100 ARMword va);
101
102/* mmu cache search by set/index
103 *
104 * @state :ARMul_State
105 * @cache_t :cache_t to search
106 * @index :set/index value.
107 *
108 * $ NULL: no cache match
109 * cache :cache matched
110 * */
111
112cache_line_t *mmu_cache_search_by_index (ARMul_State * state,
113 cache_s * cache_t, ARMword index);
114
115/* mmu cache alloc
116 *
117 * @state :ARMul_State
118 * @cache_t :cache_t to alloc from
119 * @va :virtual address that require cache alloc, need not cache aligned
120 * @pa :physical address of va
121 *
122 * $ cache_alloced, always alloc OK
123 */
124cache_line_t *mmu_cache_alloc (ARMul_State * state, cache_s * cache_t,
125 ARMword va, ARMword pa);
126
127/* mmu_cache_write_back write cache data to memory
128 *
129 * @state:
130 * @cache_t :cache_t of the cache line
131 * @cache : cache line
132 */
133void
134mmu_cache_write_back (ARMul_State * state, cache_s * cache_t,
135 cache_line_t * cache);
136
137/* mmu_cache_clean: clean a cache of va in cache_t
138 *
139 * @state :ARMul_State
140 * @cache_t :cache_t to clean
141 * @va :virtaul address
142 */
143void mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va);
144void
145mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t,
146 ARMword index);
147
148/* mmu_cache_invalidate : invalidate a cache of va
149 *
150 * @state :ARMul_State
151 * @cache_t :cache_t to invalid
152 * @va :virt_addr to invalid
153 */
154void
155mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va);
156
157void
158mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t,
159 ARMword index);
160
161void mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t);
162
163void
164mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa);
165
166cache_line_t* mmu_cache_dirty_cache(ARMul_State * state, cache_s * cache_t);
167
168#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 @@
1/* maverick.c -- Cirrus/DSP co-processor interface.
2 Copyright (C) 2003 Free Software Foundation, Inc.
3 Contributed by Aldy Hernandez (aldyh@redhat.com).
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19#include <assert.h>
20
21#include "core/arm/interpreter/armdefs.h"
22#include "core/arm/interpreter/armemu.h"
23
24
25/*#define CIRRUS_DEBUG 1 */
26#if CIRRUS_DEBUG
27# define printfdbg printf
28#else
29# define printfdbg printf_nothing
30#endif
31
32#define POS64(i) ( (~(i)) >> 63 )
33#define NEG64(i) ( (i) >> 63 )
34
35/* Define Co-Processor instruction handlers here. */
36
37/* Here's ARMulator's DSP definition. A few things to note:
38 1) it has 16 64-bit registers and 4 72-bit accumulators
39 2) you can only access its registers with MCR and MRC. */
40
41/* We can't define these in here because this file might not be linked
42 unless the target is arm9e-*. They are defined in wrapper.c.
43 Eventually the simulator should be made to handle any coprocessor
44 at run time. */
45struct maverick_regs
46{
47 union
48 {
49 int i;
50 float f;
51 } upper;
52
53 union
54 {
55 int i;
56 float f;
57 } lower;
58};
59
60union maverick_acc_regs
61{
62 long double ld; /* Acc registers are 72-bits. */
63};
64
65struct maverick_regs DSPregs[16];
66union maverick_acc_regs DSPacc[4];
67ARMword DSPsc;
68
69#define DEST_REG (BITS (12, 15))
70#define SRC1_REG (BITS (16, 19))
71#define SRC2_REG (BITS (0, 3))
72
73static int lsw_int_index, msw_int_index;
74static int lsw_float_index, msw_float_index;
75
76static double mv_getRegDouble (int);
77static long long mv_getReg64int (int);
78static void mv_setRegDouble (int, double val);
79static void mv_setReg64int (int, long long val);
80
81static union
82{
83 double d;
84 long long ll;
85 int ints[2];
86} reg_conv;
87
88static void
89printf_nothing (const char *foo, ...)
90{
91}
92
93static void
94cirrus_not_implemented (const char *insn)
95{
96 fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn);
97 fprintf (stderr, "aborting!\n");
98
99 // skyeye_exit (1);
100}
101
102static unsigned
103DSPInit (ARMul_State * state)
104{
105 NOTICE_LOG(ARM11, "ARMul_ConsolePrint: DSP present");
106 return TRUE;
107}
108
109unsigned
110DSPMRC4 (ARMul_State * state,
111 unsigned type, ARMword instr, ARMword * value)
112{
113 switch (BITS (5, 7)) {
114 case 0: /* cfmvrdl */
115 /* Move lower half of a DF stored in a DSP reg into an Arm reg. */
116 printfdbg ("cfmvrdl\n");
117 printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i);
118 printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
119
120 *value = (ARMword) DSPregs[SRC1_REG].lower.i;
121 break;
122
123 case 1: /* cfmvrdh */
124 /* Move upper half of a DF stored in a DSP reg into an Arm reg. */
125 printfdbg ("cfmvrdh\n");
126 printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i);
127 printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
128
129 *value = (ARMword) DSPregs[SRC1_REG].upper.i;
130 break;
131
132 case 2: /* cfmvrs */
133 /* Move SF from upper half of a DSP register to an Arm register. */
134 *value = (ARMword) DSPregs[SRC1_REG].upper.i;
135 printfdbg ("cfmvrs = mvf%d <-- %f\n",
136 SRC1_REG, DSPregs[SRC1_REG].upper.f);
137 break;
138
139#ifdef doesnt_work
140 case 4: /* cfcmps */
141 {
142 float a, b;
143 int n, z, c, v;
144
145 a = DSPregs[SRC1_REG].upper.f;
146 b = DSPregs[SRC2_REG].upper.f;
147
148 printfdbg ("cfcmps\n");
149 printfdbg ("\tcomparing %f and %f\n", a, b);
150
151 z = a == b; /* zero */
152 n = a != b; /* negative */
153 v = a > b; /* overflow */
154 c = 0; /* carry */
155 *value = (n << 31) | (z << 30) | (c << 29) | (v <<
156 28);
157 break;
158 }
159
160 case 5: /* cfcmpd */
161 {
162 double a, b;
163 int n, z, c, v;
164
165 a = mv_getRegDouble (SRC1_REG);
166 b = mv_getRegDouble (SRC2_REG);
167
168 printfdbg ("cfcmpd\n");
169 printfdbg ("\tcomparing %g and %g\n", a, b);
170
171 z = a == b; /* zero */
172 n = a != b; /* negative */
173 v = a > b; /* overflow */
174 c = 0; /* carry */
175 *value = (n << 31) | (z << 30) | (c << 29) | (v <<
176 28);
177 break;
178 }
179#else
180 case 4: /* cfcmps */
181 {
182 float a, b;
183 int n, z, c, v;
184
185 a = DSPregs[SRC1_REG].upper.f;
186 b = DSPregs[SRC2_REG].upper.f;
187
188 printfdbg ("cfcmps\n");
189 printfdbg ("\tcomparing %f and %f\n", a, b);
190
191 z = a == b; /* zero */
192 n = a < b; /* negative */
193 c = a > b; /* carry */
194 v = 0; /* fixme */
195 printfdbg ("\tz = %d, n = %d\n", z, n);
196 *value = (n << 31) | (z << 30) | (c << 29) | (v <<
197 28);
198 break;
199 }
200
201 case 5: /* cfcmpd */
202 {
203 double a, b;
204 int n, z, c, v;
205
206 a = mv_getRegDouble (SRC1_REG);
207 b = mv_getRegDouble (SRC2_REG);
208
209 printfdbg ("cfcmpd\n");
210 printfdbg ("\tcomparing %g and %g\n", a, b);
211
212 z = a == b; /* zero */
213 n = a < b; /* negative */
214 c = a > b; /* carry */
215 v = 0; /* fixme */
216 *value = (n << 31) | (z << 30) | (c << 29) | (v <<
217 28);
218 break;
219 }
220#endif
221 default:
222 fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr);
223 cirrus_not_implemented ("unknown");
224 break;
225 }
226
227 return ARMul_DONE;
228}
229
230unsigned
231DSPMRC5 (ARMul_State * state,
232 unsigned type, ARMword instr, ARMword * value)
233{
234 switch (BITS (5, 7)) {
235 case 0: /* cfmvr64l */
236 /* Move lower half of 64bit int from Cirrus to Arm. */
237 *value = (ARMword) DSPregs[SRC1_REG].lower.i;
238 printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n",
239 DEST_REG, (int) *value);
240 break;
241
242 case 1: /* cfmvr64h */
243 /* Move upper half of 64bit int from Cirrus to Arm. */
244 *value = (ARMword) DSPregs[SRC1_REG].upper.i;
245 printfdbg ("cfmvr64h <-- %d\n", (int) *value);
246 break;
247
248 case 4: /* cfcmp32 */
249 {
250 int res;
251 int n, z, c, v;
252 unsigned int a, b;
253
254 printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", SRC1_REG,
255 SRC2_REG);
256
257 /* FIXME: see comment for cfcmps. */
258 a = DSPregs[SRC1_REG].lower.i;
259 b = DSPregs[SRC2_REG].lower.i;
260
261 res = DSPregs[SRC1_REG].lower.i -
262 DSPregs[SRC2_REG].lower.i;
263 /* zero */
264 z = res == 0;
265 /* negative */
266 n = res < 0;
267 /* overflow */
268 v = SubOverflow (DSPregs[SRC1_REG].lower.i,
269 DSPregs[SRC2_REG].lower.i, res);
270 /* carry */
271 c = (NEG (a) && POS (b) ||
272 (NEG (a) && POS (res)) || (POS (b)
273 && POS (res)));
274
275 *value = (n << 31) | (z << 30) | (c << 29) | (v <<
276 28);
277 break;
278 }
279
280 case 5: /* cfcmp64 */
281 {
282 long long res;
283 int n, z, c, v;
284 unsigned long long a, b;
285
286 printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", SRC1_REG,
287 SRC2_REG);
288
289 /* fixme: see comment for cfcmps. */
290
291 a = mv_getReg64int (SRC1_REG);
292 b = mv_getReg64int (SRC2_REG);
293
294 res = mv_getReg64int (SRC1_REG) -
295 mv_getReg64int (SRC2_REG);
296 /* zero */
297 z = res == 0;
298 /* negative */
299 n = res < 0;
300 /* overflow */
301 v = ((NEG64 (a) && POS64 (b) && POS64 (res))
302 || (POS64 (a) && NEG64 (b) && NEG64 (res)));
303 /* carry */
304 c = (NEG64 (a) && POS64 (b) ||
305 (NEG64 (a) && POS64 (res)) || (POS64 (b)
306 && POS64 (res)));
307
308 *value = (n << 31) | (z << 30) | (c << 29) | (v <<
309 28);
310 break;
311 }
312
313 default:
314 fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr);
315 cirrus_not_implemented ("unknown");
316 break;
317 }
318
319 return ARMul_DONE;
320}
321
322unsigned
323DSPMRC6 (ARMul_State * state,
324 unsigned type, ARMword instr, ARMword * value)
325{
326 switch (BITS (5, 7)) {
327 case 0: /* cfmval32 */
328 cirrus_not_implemented ("cfmval32");
329 break;
330
331 case 1: /* cfmvam32 */
332 cirrus_not_implemented ("cfmvam32");
333 break;
334
335 case 2: /* cfmvah32 */
336 cirrus_not_implemented ("cfmvah32");
337 break;
338
339 case 3: /* cfmva32 */
340 cirrus_not_implemented ("cfmva32");
341 break;
342
343 case 4: /* cfmva64 */
344 cirrus_not_implemented ("cfmva64");
345 break;
346
347 case 5: /* cfmvsc32 */
348 cirrus_not_implemented ("cfmvsc32");
349 break;
350
351 default:
352 fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr);
353 cirrus_not_implemented ("unknown");
354 break;
355 }
356
357 return ARMul_DONE;
358}
359
360unsigned
361DSPMCR4 (ARMul_State * state,
362 unsigned type, ARMword instr, ARMword value)
363{
364 switch (BITS (5, 7)) {
365 case 0: /* cfmvdlr */
366 /* Move the lower half of a DF value from an Arm register into
367 the lower half of a Cirrus register. */
368 printfdbg ("cfmvdlr <-- 0x%x\n", (int) value);
369 DSPregs[SRC1_REG].lower.i = (int) value;
370 break;
371
372 case 1: /* cfmvdhr */
373 /* Move the upper half of a DF value from an Arm register into
374 the upper half of a Cirrus register. */
375 printfdbg ("cfmvdhr <-- 0x%x\n", (int) value);
376 DSPregs[SRC1_REG].upper.i = (int) value;
377 break;
378
379 case 2: /* cfmvsr */
380 /* Move SF from Arm register into upper half of Cirrus register. */
381 printfdbg ("cfmvsr <-- 0x%x\n", (int) value);
382 DSPregs[SRC1_REG].upper.i = (int) value;
383 break;
384
385 default:
386 fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr);
387 cirrus_not_implemented ("unknown");
388 break;
389 }
390
391 return ARMul_DONE;
392}
393
394unsigned
395DSPMCR5 (ARMul_State * state,
396 unsigned type, ARMword instr, ARMword value)
397{
398 union
399 {
400 int s;
401 unsigned int us;
402 } val;
403
404 switch (BITS (5, 7)) {
405 case 0: /* cfmv64lr */
406 /* Move lower half of a 64bit int from an ARM register into the
407 lower half of a DSP register and sign extend it. */
408 printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG,
409 (int) value);
410 DSPregs[SRC1_REG].lower.i = (int) value;
411 break;
412
413 case 1: /* cfmv64hr */
414 /* Move upper half of a 64bit int from an ARM register into the
415 upper half of a DSP register. */
416 printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n",
417 SRC1_REG, (int) value);
418 DSPregs[SRC1_REG].upper.i = (int) value;
419 break;
420
421 case 2: /* cfrshl32 */
422 printfdbg ("cfrshl32\n");
423 val.us = value;
424 if (val.s > 0)
425 DSPregs[SRC2_REG].lower.i =
426 DSPregs[SRC1_REG].lower.i << value;
427 else
428 DSPregs[SRC2_REG].lower.i =
429 DSPregs[SRC1_REG].lower.i >> -value;
430 break;
431
432 case 3: /* cfrshl64 */
433 printfdbg ("cfrshl64\n");
434 val.us = value;
435 if (val.s > 0)
436 mv_setReg64int (SRC2_REG,
437 mv_getReg64int (SRC1_REG) << value);
438 else
439 mv_setReg64int (SRC2_REG,
440 mv_getReg64int (SRC1_REG) >> -value);
441 break;
442
443 default:
444 fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr);
445 cirrus_not_implemented ("unknown");
446 break;
447 }
448
449 return ARMul_DONE;
450}
451
452unsigned
453DSPMCR6 (ARMul_State * state,
454 unsigned type, ARMword instr, ARMword value)
455{
456 switch (BITS (5, 7)) {
457 case 0: /* cfmv32al */
458 cirrus_not_implemented ("cfmv32al");
459 break;
460
461 case 1: /* cfmv32am */
462 cirrus_not_implemented ("cfmv32am");
463 break;
464
465 case 2: /* cfmv32ah */
466 cirrus_not_implemented ("cfmv32ah");
467 break;
468
469 case 3: /* cfmv32a */
470 cirrus_not_implemented ("cfmv32a");
471 break;
472
473 case 4: /* cfmv64a */
474 cirrus_not_implemented ("cfmv64a");
475 break;
476
477 case 5: /* cfmv32sc */
478 cirrus_not_implemented ("cfmv32sc");
479 break;
480
481 default:
482 fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr);
483 cirrus_not_implemented ("unknown");
484 break;
485 }
486
487 return ARMul_DONE;
488}
489
490unsigned
491DSPLDC4 (ARMul_State * state,
492 unsigned type, ARMword instr, ARMword data)
493{
494 static unsigned words;
495
496 if (type != ARMul_DATA) {
497 words = 0;
498 return ARMul_DONE;
499 }
500
501 if (BIT (22)) { /* it's a long access, get two words */
502 /* cfldrd */
503
504 printfdbg
505 ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n",
506 data, words, state->bigendSig, DEST_REG);
507
508 if (words == 0) {
509 if (state->bigendSig)
510 DSPregs[DEST_REG].upper.i = (int) data;
511 else
512 DSPregs[DEST_REG].lower.i = (int) data;
513 }
514 else {
515 if (state->bigendSig)
516 DSPregs[DEST_REG].lower.i = (int) data;
517 else
518 DSPregs[DEST_REG].upper.i = (int) data;
519 }
520
521 ++words;
522
523 if (words == 2) {
524 printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG,
525 mv_getRegDouble (DEST_REG));
526
527 return ARMul_DONE;
528 }
529 else
530 return ARMul_INC;
531 }
532 else {
533 /* Get just one word. */
534
535 /* cfldrs */
536 printfdbg ("cfldrs\n");
537
538 DSPregs[DEST_REG].upper.i = (int) data;
539
540 printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG,
541 DSPregs[DEST_REG].upper.f);
542
543 return ARMul_DONE;
544 }
545}
546
547unsigned
548DSPLDC5 (ARMul_State * state,
549 unsigned type, ARMword instr, ARMword data)
550{
551 static unsigned words;
552
553 if (type != ARMul_DATA) {
554 words = 0;
555 return ARMul_DONE;
556 }
557
558 if (BIT (22)) {
559 /* It's a long access, get two words. */
560
561 /* cfldr64 */
562 printfdbg ("cfldr64: %d\n", data);
563
564 if (words == 0) {
565 if (state->bigendSig)
566 DSPregs[DEST_REG].upper.i = (int) data;
567 else
568 DSPregs[DEST_REG].lower.i = (int) data;
569 }
570 else {
571 if (state->bigendSig)
572 DSPregs[DEST_REG].lower.i = (int) data;
573 else
574 DSPregs[DEST_REG].upper.i = (int) data;
575 }
576
577 ++words;
578
579 if (words == 2) {
580 printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG,
581 mv_getReg64int (DEST_REG));
582
583 return ARMul_DONE;
584 }
585 else
586 return ARMul_INC;
587 }
588 else {
589 /* Get just one word. */
590
591 /* cfldr32 */
592 printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data);
593
594 /* 32bit ints should be sign extended to 64bits when loaded. */
595 mv_setReg64int (DEST_REG, (long long) data);
596
597 return ARMul_DONE;
598 }
599}
600
601unsigned
602DSPSTC4 (ARMul_State * state,
603 unsigned type, ARMword instr, ARMword * data)
604{
605 static unsigned words;
606
607 if (type != ARMul_DATA) {
608 words = 0;
609 return ARMul_DONE;
610 }
611
612 if (BIT (22)) {
613 /* It's a long access, get two words. */
614 /* cfstrd */
615 printfdbg ("cfstrd\n");
616
617 if (words == 0) {
618 if (state->bigendSig)
619 *data = (ARMword) DSPregs[DEST_REG].upper.i;
620 else
621 *data = (ARMword) DSPregs[DEST_REG].lower.i;
622 }
623 else {
624 if (state->bigendSig)
625 *data = (ARMword) DSPregs[DEST_REG].lower.i;
626 else
627 *data = (ARMword) DSPregs[DEST_REG].upper.i;
628 }
629
630 ++words;
631
632 if (words == 2) {
633 printfdbg ("\tmem = mvd%d = %g\n", DEST_REG,
634 mv_getRegDouble (DEST_REG));
635
636 return ARMul_DONE;
637 }
638 else
639 return ARMul_INC;
640 }
641 else {
642 /* Get just one word. */
643 /* cfstrs */
644 printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG,
645 DSPregs[DEST_REG].upper.f);
646
647 *data = (ARMword) DSPregs[DEST_REG].upper.i;
648
649 return ARMul_DONE;
650 }
651}
652
653unsigned
654DSPSTC5 (ARMul_State * state,
655 unsigned type, ARMword instr, ARMword * data)
656{
657 static unsigned words;
658
659 if (type != ARMul_DATA) {
660 words = 0;
661 return ARMul_DONE;
662 }
663
664 if (BIT (22)) {
665 /* It's a long access, store two words. */
666 /* cfstr64 */
667 printfdbg ("cfstr64\n");
668
669 if (words == 0) {
670 if (state->bigendSig)
671 *data = (ARMword) DSPregs[DEST_REG].upper.i;
672 else
673 *data = (ARMword) DSPregs[DEST_REG].lower.i;
674 }
675 else {
676 if (state->bigendSig)
677 *data = (ARMword) DSPregs[DEST_REG].lower.i;
678 else
679 *data = (ARMword) DSPregs[DEST_REG].upper.i;
680 }
681
682 ++words;
683
684 if (words == 2) {
685 printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG,
686 mv_getReg64int (DEST_REG));
687
688 return ARMul_DONE;
689 }
690 else
691 return ARMul_INC;
692 }
693 else {
694 /* Store just one word. */
695 /* cfstr32 */
696 *data = (ARMword) DSPregs[DEST_REG].lower.i;
697
698 printfdbg ("cfstr32 MEM = %d\n", (int) *data);
699
700 return ARMul_DONE;
701 }
702}
703
704unsigned
705DSPCDP4 (ARMul_State * state, unsigned type, ARMword instr)
706{
707 int opcode2;
708
709 opcode2 = BITS (5, 7);
710
711 switch (BITS (20, 21)) {
712 case 0:
713 switch (opcode2) {
714 case 0: /* cfcpys */
715 printfdbg ("cfcpys mvf%d = mvf%d = %f\n",
716 DEST_REG, SRC1_REG,
717 DSPregs[SRC1_REG].upper.f);
718 DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f;
719 break;
720
721 case 1: /* cfcpyd */
722 printfdbg ("cfcpyd mvd%d = mvd%d = %g\n",
723 DEST_REG, SRC1_REG,
724 mv_getRegDouble (SRC1_REG));
725 mv_setRegDouble (DEST_REG,
726 mv_getRegDouble (SRC1_REG));
727 break;
728
729 case 2: /* cfcvtds */
730 printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n",
731 DEST_REG, SRC1_REG,
732 (float) mv_getRegDouble (SRC1_REG));
733 DSPregs[DEST_REG].upper.f =
734 (float) mv_getRegDouble (SRC1_REG);
735 break;
736
737 case 3: /* cfcvtsd */
738 printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n",
739 DEST_REG, SRC1_REG,
740 (double) DSPregs[SRC1_REG].upper.f);
741 mv_setRegDouble (DEST_REG,
742 (double) DSPregs[SRC1_REG].upper.f);
743 break;
744
745 case 4: /* cfcvt32s */
746 printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n",
747 DEST_REG, SRC1_REG,
748 (float) DSPregs[SRC1_REG].lower.i);
749 DSPregs[DEST_REG].upper.f =
750 (float) DSPregs[SRC1_REG].lower.i;
751 break;
752
753 case 5: /* cfcvt32d */
754 printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n",
755 DEST_REG, SRC1_REG,
756 (double) DSPregs[SRC1_REG].lower.i);
757 mv_setRegDouble (DEST_REG,
758 (double) DSPregs[SRC1_REG].lower.i);
759 break;
760
761 case 6: /* cfcvt64s */
762 printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n",
763 DEST_REG, SRC1_REG,
764 (float) mv_getReg64int (SRC1_REG));
765 DSPregs[DEST_REG].upper.f =
766 (float) mv_getReg64int (SRC1_REG);
767 break;
768
769 case 7: /* cfcvt64d */
770 printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n",
771 DEST_REG, SRC1_REG,
772 (double) mv_getReg64int (SRC1_REG));
773 mv_setRegDouble (DEST_REG,
774 (double) mv_getReg64int (SRC1_REG));
775 break;
776 }
777 break;
778
779 case 1:
780 switch (opcode2) {
781 case 0: /* cfmuls */
782 printfdbg ("cfmuls mvf%d = mvf%d = %f\n",
783 DEST_REG,
784 SRC1_REG,
785 DSPregs[SRC1_REG].upper.f *
786 DSPregs[SRC2_REG].upper.f);
787
788 DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
789 * DSPregs[SRC2_REG].upper.f;
790 break;
791
792 case 1: /* cfmuld */
793 printfdbg ("cfmuld mvd%d = mvd%d = %g\n",
794 DEST_REG,
795 SRC1_REG,
796 mv_getRegDouble (SRC1_REG) *
797 mv_getRegDouble (SRC2_REG));
798
799 mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
800 * mv_getRegDouble (SRC2_REG));
801 break;
802
803 default:
804 fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n",
805 instr);
806 cirrus_not_implemented ("unknown");
807 break;
808 }
809 break;
810
811 case 3:
812 switch (opcode2) {
813 case 0: /* cfabss */
814 DSPregs[DEST_REG].upper.f =
815 (DSPregs[SRC1_REG].upper.f <
816 0.0F ? -DSPregs[SRC1_REG].upper.
817 f : DSPregs[SRC1_REG].upper.f);
818 printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", DEST_REG,
819 SRC1_REG, DSPregs[DEST_REG].upper.f);
820 break;
821
822 case 1: /* cfabsd */
823 mv_setRegDouble (DEST_REG,
824 (mv_getRegDouble (SRC1_REG) < 0.0 ?
825 -mv_getRegDouble (SRC1_REG)
826 : mv_getRegDouble (SRC1_REG)));
827 printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n",
828 DEST_REG, SRC1_REG,
829 mv_getRegDouble (DEST_REG));
830 break;
831
832 case 2: /* cfnegs */
833 DSPregs[DEST_REG].upper.f =
834 -DSPregs[SRC1_REG].upper.f;
835 printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", DEST_REG,
836 SRC1_REG, DSPregs[DEST_REG].upper.f);
837 break;
838
839 case 3: /* cfnegd */
840 mv_setRegDouble (DEST_REG,
841 -mv_getRegDouble (SRC1_REG));
842 printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", DEST_REG,
843 mv_getRegDouble (DEST_REG));
844 break;
845
846 case 4: /* cfadds */
847 DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
848 + DSPregs[SRC2_REG].upper.f;
849 printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n",
850 DEST_REG, SRC1_REG, SRC2_REG,
851 DSPregs[DEST_REG].upper.f);
852 break;
853
854 case 5: /* cfaddd */
855 mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
856 + mv_getRegDouble (SRC2_REG));
857 printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n",
858 DEST_REG,
859 SRC1_REG, SRC2_REG,
860 mv_getRegDouble (DEST_REG));
861 break;
862
863 case 6: /* cfsubs */
864 DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
865 - DSPregs[SRC2_REG].upper.f;
866 printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n",
867 DEST_REG, SRC1_REG, SRC2_REG,
868 DSPregs[DEST_REG].upper.f);
869 break;
870
871 case 7: /* cfsubd */
872 mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
873 - mv_getRegDouble (SRC2_REG));
874 printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n",
875 DEST_REG,
876 SRC1_REG, SRC2_REG,
877 mv_getRegDouble (DEST_REG));
878 break;
879 }
880 break;
881
882 default:
883 fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr);
884 cirrus_not_implemented ("unknown");
885 break;
886 }
887
888 return ARMul_DONE;
889}
890
891unsigned
892DSPCDP5 (ARMul_State * state, unsigned type, ARMword instr)
893{
894 int opcode2;
895 char shift;
896
897 opcode2 = BITS (5, 7);
898
899 /* Shift constants are 7bit signed numbers in bits 0..3|5..7. */
900 shift = BITS (0, 3) | (BITS (5, 7)) << 4;
901 if (shift & 0x40)
902 shift |= 0xc0;
903
904 switch (BITS (20, 21)) {
905 case 0:
906 /* cfsh32 */
907 printfdbg ("cfsh32 %s amount=%d\n",
908 shift < 0 ? "right" : "left", shift);
909 if (shift < 0)
910 /* Negative shift is a right shift. */
911 DSPregs[DEST_REG].lower.i =
912 DSPregs[SRC1_REG].lower.i >> -shift;
913 else
914 /* Positive shift is a left shift. */
915 DSPregs[DEST_REG].lower.i =
916 DSPregs[SRC1_REG].lower.i << shift;
917 break;
918
919 case 1:
920 switch (opcode2) {
921 case 0: /* cfmul32 */
922 DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
923 * DSPregs[SRC2_REG].lower.i;
924 printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n",
925 DEST_REG, SRC1_REG, SRC2_REG,
926 DSPregs[DEST_REG].lower.i);
927 break;
928
929 case 1: /* cfmul64 */
930 mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
931 * mv_getReg64int (SRC2_REG));
932 printfdbg
933 ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n",
934 DEST_REG, SRC1_REG, SRC2_REG,
935 mv_getReg64int (DEST_REG));
936 break;
937
938 case 2: /* cfmac32 */
939 DSPregs[DEST_REG].lower.i
940 +=
941 DSPregs[SRC1_REG].lower.i *
942 DSPregs[SRC2_REG].lower.i;
943 printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n",
944 DEST_REG, SRC1_REG, SRC2_REG,
945 DSPregs[DEST_REG].lower.i);
946 break;
947
948 case 3: /* cfmsc32 */
949 DSPregs[DEST_REG].lower.i
950 -=
951 DSPregs[SRC1_REG].lower.i *
952 DSPregs[SRC2_REG].lower.i;
953 printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n",
954 DEST_REG, SRC1_REG, SRC2_REG,
955 DSPregs[DEST_REG].lower.i);
956 break;
957
958 case 4: /* cfcvts32 */
959 /* fixme: this should round */
960 DSPregs[DEST_REG].lower.i =
961 (int) DSPregs[SRC1_REG].upper.f;
962 printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", DEST_REG,
963 SRC1_REG, DSPregs[DEST_REG].lower.i);
964 break;
965
966 case 5: /* cfcvtd32 */
967 /* fixme: this should round */
968 DSPregs[DEST_REG].lower.i =
969 (int) mv_getRegDouble (SRC1_REG);
970 printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", DEST_REG,
971 SRC1_REG, DSPregs[DEST_REG].lower.i);
972 break;
973
974 case 6: /* cftruncs32 */
975 DSPregs[DEST_REG].lower.i =
976 (int) DSPregs[SRC1_REG].upper.f;
977 printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n",
978 DEST_REG, SRC1_REG,
979 DSPregs[DEST_REG].lower.i);
980 break;
981
982 case 7: /* cftruncd32 */
983 DSPregs[DEST_REG].lower.i =
984 (int) mv_getRegDouble (SRC1_REG);
985 printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n",
986 DEST_REG, SRC1_REG,
987 DSPregs[DEST_REG].lower.i);
988 break;
989 }
990 break;
991
992 case 2:
993 /* cfsh64 */
994 printfdbg ("cfsh64\n");
995
996 if (shift < 0)
997 /* Negative shift is a right shift. */
998 mv_setReg64int (DEST_REG,
999 mv_getReg64int (SRC1_REG) >> -shift);
1000 else
1001 /* Positive shift is a left shift. */
1002 mv_setReg64int (DEST_REG,
1003 mv_getReg64int (SRC1_REG) << shift);
1004 printfdbg ("\t%llx\n", mv_getReg64int (DEST_REG));
1005 break;
1006
1007 case 3:
1008 switch (opcode2) {
1009 case 0: /* cfabs32 */
1010 DSPregs[DEST_REG].lower.i =
1011 (DSPregs[SRC1_REG].lower.i <
1012 0 ? -DSPregs[SRC1_REG].lower.
1013 i : DSPregs[SRC1_REG].lower.i);
1014 printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n",
1015 DEST_REG, SRC1_REG, SRC2_REG,
1016 DSPregs[DEST_REG].lower.i);
1017 break;
1018
1019 case 1: /* cfabs64 */
1020 mv_setReg64int (DEST_REG,
1021 (mv_getReg64int (SRC1_REG) < 0
1022 ? -mv_getReg64int (SRC1_REG)
1023 : mv_getReg64int (SRC1_REG)));
1024 printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n",
1025 DEST_REG, SRC1_REG, SRC2_REG,
1026 mv_getReg64int (DEST_REG));
1027 break;
1028
1029 case 2: /* cfneg32 */
1030 DSPregs[DEST_REG].lower.i =
1031 -DSPregs[SRC1_REG].lower.i;
1032 printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n",
1033 DEST_REG, SRC1_REG, SRC2_REG,
1034 DSPregs[DEST_REG].lower.i);
1035 break;
1036
1037 case 3: /* cfneg64 */
1038 mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG));
1039 printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n",
1040 DEST_REG, SRC1_REG, SRC2_REG,
1041 mv_getReg64int (DEST_REG));
1042 break;
1043
1044 case 4: /* cfadd32 */
1045 DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
1046 + DSPregs[SRC2_REG].lower.i;
1047 printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n",
1048 DEST_REG, SRC1_REG, SRC2_REG,
1049 DSPregs[DEST_REG].lower.i);
1050 break;
1051
1052 case 5: /* cfadd64 */
1053 mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
1054 + mv_getReg64int (SRC2_REG));
1055 printfdbg
1056 ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n",
1057 DEST_REG, SRC1_REG, SRC2_REG,
1058 mv_getReg64int (DEST_REG));
1059 break;
1060
1061 case 6: /* cfsub32 */
1062 DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
1063 - DSPregs[SRC2_REG].lower.i;
1064 printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n",
1065 DEST_REG, SRC1_REG, SRC2_REG,
1066 DSPregs[DEST_REG].lower.i);
1067 break;
1068
1069 case 7: /* cfsub64 */
1070 mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
1071 - mv_getReg64int (SRC2_REG));
1072 printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n",
1073 DEST_REG, SRC1_REG, SRC2_REG,
1074 mv_getReg64int (DEST_REG));
1075 break;
1076 }
1077 break;
1078
1079 default:
1080 fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr);
1081 cirrus_not_implemented ("unknown");
1082 break;
1083 }
1084
1085 return ARMul_DONE;
1086}
1087
1088unsigned
1089DSPCDP6 (ARMul_State * state, unsigned type, ARMword instr)
1090{
1091 int opcode2;
1092
1093 opcode2 = BITS (5, 7);
1094
1095 switch (BITS (20, 21)) {
1096 case 0:
1097 /* cfmadd32 */
1098 cirrus_not_implemented ("cfmadd32");
1099 break;
1100
1101 case 1:
1102 /* cfmsub32 */
1103 cirrus_not_implemented ("cfmsub32");
1104 break;
1105
1106 case 2:
1107 /* cfmadda32 */
1108 cirrus_not_implemented ("cfmadda32");
1109 break;
1110
1111 case 3:
1112 /* cfmsuba32 */
1113 cirrus_not_implemented ("cfmsuba32");
1114 break;
1115
1116 default:
1117 fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr);
1118 }
1119
1120 return ARMul_DONE;
1121}
1122
1123/* Conversion functions.
1124
1125 32-bit integers are stored in the LOWER half of a 64-bit physical
1126 register.
1127
1128 Single precision floats are stored in the UPPER half of a 64-bit
1129 physical register. */
1130
1131static double
1132mv_getRegDouble (int regnum)
1133{
1134 reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i;
1135 reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i;
1136 return reg_conv.d;
1137}
1138
1139static void
1140mv_setRegDouble (int regnum, double val)
1141{
1142 reg_conv.d = val;
1143 DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index];
1144 DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index];
1145}
1146
1147static long long
1148mv_getReg64int (int regnum)
1149{
1150 reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i;
1151 reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i;
1152 return reg_conv.ll;
1153}
1154
1155static void
1156mv_setReg64int (int regnum, long long val)
1157{
1158 reg_conv.ll = val;
1159 DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index];
1160 DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index];
1161}
1162
1163/* Compute LSW in a double and a long long. */
1164
1165void
1166mv_compute_host_endianness (ARMul_State * state)
1167{
1168 static union
1169 {
1170 long long ll;
1171 int ints[2];
1172 int i;
1173 double d;
1174 float floats[2];
1175 float f;
1176 } conv;
1177
1178 /* Calculate where's the LSW in a 64bit int. */
1179 conv.ll = 45;
1180
1181 if (conv.ints[0] == 0) {
1182 msw_int_index = 0;
1183 lsw_int_index = 1;
1184 }
1185 else {
1186 assert (conv.ints[1] == 0);
1187 msw_int_index = 1;
1188 lsw_int_index = 0;
1189 }
1190
1191 /* Calculate where's the LSW in a double. */
1192 conv.d = 3.0;
1193
1194 if (conv.ints[0] == 0) {
1195 msw_float_index = 0;
1196 lsw_float_index = 1;
1197 }
1198 else {
1199 assert (conv.ints[1] == 0);
1200 msw_float_index = 1;
1201 lsw_float_index = 0;
1202 }
1203
1204 printfdbg ("lsw_int_index %d\n", lsw_int_index);
1205 printfdbg ("lsw_float_index %d\n", lsw_float_index);
1206}
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 @@
1#include "core/arm/interpreter/armdefs.h"
2
3/*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu*/
4ARMword rb_masks[] = {
5 0x0, //RB_INVALID
6 4, //RB_1
7 16, //RB_4
8 32, //RB_8
9};
10
11/*mmu_rb_init
12 * @rb_t :rb_t to init
13 * @num :number of entry
14 * */
15int
16mmu_rb_init (rb_s * rb_t, int num)
17{
18 int i;
19 rb_entry_t *entrys;
20
21 entrys = (rb_entry_t *) malloc (sizeof (*entrys) * num);
22 if (entrys == NULL) {
23 printf ("SKYEYE:mmu_rb_init malloc error\n");
24 return -1;
25 }
26 for (i = 0; i < num; i++) {
27 entrys[i].type = RB_INVALID;
28 entrys[i].fault = NO_FAULT;
29 }
30
31 rb_t->entrys = entrys;
32 rb_t->num = num;
33 return 0;
34}
35
36/*mmu_rb_exit*/
37void
38mmu_rb_exit (rb_s * rb_t)
39{
40 free (rb_t->entrys);
41};
42
43/*mmu_rb_search
44 * @rb_t :rb_t to serach
45 * @va :va address to math
46 *
47 * $ NULL :not match
48 * NO-NULL:
49 * */
50rb_entry_t *
51mmu_rb_search (rb_s * rb_t, ARMword va)
52{
53 int i;
54 rb_entry_t *rb = rb_t->entrys;
55
56 DEBUG_LOG(ARM11, "va = %x\n", va);
57 for (i = 0; i < rb_t->num; i++, rb++) {
58 //2004-06-06 lyh bug from wenye@cs.ucsb.edu
59 if (rb->type) {
60 if ((va >= rb->va)
61 && (va < (rb->va + rb_masks[rb->type])))
62 return rb;
63 }
64 }
65 return NULL;
66};
67
68void
69mmu_rb_invalidate_entry (rb_s * rb_t, int i)
70{
71 rb_t->entrys[i].type = RB_INVALID;
72}
73
74void
75mmu_rb_invalidate_all (rb_s * rb_t)
76{
77 int i;
78
79 for (i = 0; i < rb_t->num; i++)
80 mmu_rb_invalidate_entry (rb_t, i);
81};
82
83void
84mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, int type, ARMword va)
85{
86 rb_entry_t *rb;
87 int i;
88 ARMword max_start, min_end;
89 fault_t fault;
90 tlb_entry_t *tlb;
91
92 /*align va according to type */
93 va &= ~(rb_masks[type] - 1);
94 /*invalidate all RB match [va, va + rb_masks[type]] */
95 for (rb = rb_t->entrys, i = 0; i < rb_t->num; i++, rb++) {
96 if (rb->type) {
97 max_start = max (va, rb->va);
98 min_end =
99 min (va + rb_masks[type],
100 rb->va + rb_masks[rb->type]);
101 if (max_start < min_end)
102 rb->type = RB_INVALID;
103 }
104 }
105 /*load word */
106 rb = &rb_t->entrys[i_rb];
107 rb->type = type;
108 fault = translate (state, va, D_TLB (), &tlb);
109 if (fault) {
110 rb->fault = fault;
111 return;
112 }
113 fault = check_access (state, va, tlb, 1);
114 if (fault) {
115 rb->fault = fault;
116 return;
117 }
118
119 rb->fault = NO_FAULT;
120 va = tlb_va_to_pa (tlb, va);
121 //2004-06-06 lyh bug from wenye@cs.ucsb.edu
122 for (i = 0; i < (rb_masks[type] / 4); i++, va += WORD_SIZE) {
123 //rb->data[i] = mem_read_word (state, va);
124 bus_read(32, va, &rb->data[i]);
125 };
126}
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 @@
1#ifndef _MMU_RB_H
2#define _MMU_RB_H
3
4enum rb_type_t
5{
6 RB_INVALID = 0, //invalid
7 RB_1, //1 word
8 RB_4, //4 word
9 RB_8, //8 word
10};
11
12/*bytes of each rb_type*/
13extern ARMword rb_masks[];
14
15#define RB_WORD_NUM 8
16typedef struct rb_entry_s
17{
18 ARMword data[RB_WORD_NUM]; //array to store data
19 ARMword va; //first word va
20 int type; //rb type
21 fault_t fault; //fault set by rb alloc
22} rb_entry_t;
23
24typedef struct rb_s
25{
26 int num;
27 rb_entry_t *entrys;
28} rb_s;
29
30/*mmu_rb_init
31 * @rb_t :rb_t to init
32 * @num :number of entry
33 * */
34int mmu_rb_init (rb_s * rb_t, int num);
35
36/*mmu_rb_exit*/
37void mmu_rb_exit (rb_s * rb_t);
38
39
40/*mmu_rb_search
41 * @rb_t :rb_t to serach
42 * @va :va address to math
43 *
44 * $ NULL :not match
45 * NO-NULL:
46 * */
47rb_entry_t *mmu_rb_search (rb_s * rb_t, ARMword va);
48
49
50void mmu_rb_invalidate_entry (rb_s * rb_t, int i);
51void mmu_rb_invalidate_all (rb_s * rb_t);
52void mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb,
53 int type, ARMword va);
54
55#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 @@
1/*
2 armmmu.c - Memory Management Unit emulation.
3 ARMulator extensions for the ARM7100 family.
4 Copyright (C) 1999 Ben Williamson
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#include <assert.h>
22#include <string.h>
23
24#include "core/arm/interpreter/armdefs.h"
25
26/**
27 * The interface of read data from bus
28 */
29int bus_read(short size, int addr, uint32_t * value) {
30 ERROR_LOG(ARM11, "unimplemented bus_read");
31 return 0;
32}
33
34/**
35 * The interface of write data from bus
36 */
37int bus_write(short size, int addr, uint32_t value) {
38 ERROR_LOG(ARM11, "unimplemented bus_write");
39 return 0;
40}
41
42
43typedef struct sa_mmu_desc_s
44{
45 int i_tlb;
46 cache_desc_t i_cache;
47
48 int d_tlb;
49 cache_desc_t main_d_cache;
50 cache_desc_t mini_d_cache;
51 int rb;
52 wb_desc_t wb;
53} sa_mmu_desc_t;
54
55static sa_mmu_desc_t sa11xx_mmu_desc = {
56 32,
57 {32, 32, 16, CACHE_WRITE_BACK},
58
59 32,
60 {32, 32, 8, CACHE_WRITE_BACK},
61 {32, 2, 8, CACHE_WRITE_BACK},
62 4,
63 //{8, 4}, for word size
64 {8, 16}, //for byte size, chy 2003-07-11
65};
66
67static fault_t sa_mmu_write (ARMul_State * state, ARMword va, ARMword data,
68 ARMword datatype);
69static fault_t sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
70 ARMword datatype);
71static fault_t update_cache (ARMul_State * state, ARMword va, ARMword data,
72 ARMword datatype, cache_line_t * cache,
73 cache_s * cache_t, ARMword real_va);
74
75void
76mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa,
77 ARMbyte * data, int n);
78int
79sa_mmu_init (ARMul_State * state)
80{
81 sa_mmu_desc_t *desc;
82 cache_desc_t *c_desc;
83
84 state->mmu.control = 0x70;
85 state->mmu.translation_table_base = 0xDEADC0DE;
86 state->mmu.domain_access_control = 0xDEADC0DE;
87 state->mmu.fault_status = 0;
88 state->mmu.fault_address = 0;
89 state->mmu.process_id = 0;
90
91 desc = &sa11xx_mmu_desc;
92 if (mmu_tlb_init (I_TLB (), desc->i_tlb)) {
93 ERROR_LOG(ARM11, "i_tlb init %d\n", -1);
94 goto i_tlb_init_error;
95 }
96
97 c_desc = &desc->i_cache;
98 if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way,
99 c_desc->set, c_desc->w_mode)) {
100 ERROR_LOG(ARM11, "i_cache init %d\n", -1);
101 goto i_cache_init_error;
102 }
103
104 if (mmu_tlb_init (D_TLB (), desc->d_tlb)) {
105 ERROR_LOG(ARM11, "d_tlb init %d\n", -1);
106 goto d_tlb_init_error;
107 }
108
109 c_desc = &desc->main_d_cache;
110 if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way,
111 c_desc->set, c_desc->w_mode)) {
112 ERROR_LOG(ARM11, "main_d_cache init %d\n", -1);
113 goto main_d_cache_init_error;
114 }
115
116 c_desc = &desc->mini_d_cache;
117 if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way,
118 c_desc->set, c_desc->w_mode)) {
119 ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1);
120 goto mini_d_cache_init_error;
121 }
122
123 if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) {
124 ERROR_LOG(ARM11, "wb init %d\n", -1);
125 goto wb_init_error;
126 }
127
128 if (mmu_rb_init (RB (), desc->rb)) {
129 ERROR_LOG(ARM11, "rb init %d\n", -1);
130 goto rb_init_error;
131 }
132 return 0;
133
134 rb_init_error:
135 mmu_wb_exit (WB ());
136 wb_init_error:
137 mmu_cache_exit (MINI_D_CACHE ());
138 mini_d_cache_init_error:
139 mmu_cache_exit (MAIN_D_CACHE ());
140 main_d_cache_init_error:
141 mmu_tlb_exit (D_TLB ());
142 d_tlb_init_error:
143 mmu_cache_exit (I_CACHE ());
144 i_cache_init_error:
145 mmu_tlb_exit (I_TLB ());
146 i_tlb_init_error:
147 return -1;
148}
149
150void
151sa_mmu_exit (ARMul_State * state)
152{
153 mmu_rb_exit (RB ());
154 mmu_wb_exit (WB ());
155 mmu_cache_exit (MINI_D_CACHE ());
156 mmu_cache_exit (MAIN_D_CACHE ());
157 mmu_tlb_exit (D_TLB ());
158 mmu_cache_exit (I_CACHE ());
159 mmu_tlb_exit (I_TLB ());
160};
161
162
163static fault_t
164sa_mmu_load_instr (ARMul_State * state, ARMword va, ARMword * instr)
165{
166 fault_t fault;
167 tlb_entry_t *tlb;
168 cache_line_t *cache;
169 int c; //cache bit
170 ARMword pa; //physical addr
171
172 static int debug_count = 0; //used for debug
173
174 DEBUG_LOG(ARM11, "va = %x\n", va);
175
176 va = mmu_pid_va_map (va);
177 if (MMU_Enabled) {
178 /*align check */
179 if ((va & (WORD_SIZE - 1)) && MMU_Aligned) {
180 DEBUG_LOG(ARM11, "align\n");
181 return ALIGNMENT_FAULT;
182 }
183 else
184 va &= ~(WORD_SIZE - 1);
185
186 /*translate tlb */
187 fault = translate (state, va, I_TLB (), &tlb);
188 if (fault) {
189 DEBUG_LOG(ARM11, "translate\n");
190 return fault;
191 }
192
193 /*check access */
194 fault = check_access (state, va, tlb, 1);
195 if (fault) {
196 DEBUG_LOG(ARM11, "check_fault\n");
197 return fault;
198 }
199 }
200
201 /*search cache no matter MMU enabled/disabled */
202 cache = mmu_cache_search (state, I_CACHE (), va);
203 if (cache) {
204 *instr = cache->data[va_cache_index (va, I_CACHE ())];
205 return NO_FAULT;
206 }
207
208 /*if MMU disabled or C flag is set alloc cache */
209 if (MMU_Disabled) {
210 c = 1;
211 pa = va;
212 }
213 else {
214 c = tlb_c_flag (tlb);
215 pa = tlb_va_to_pa (tlb, va);
216 }
217
218 if (c) {
219 int index;
220
221 debug_count++;
222 cache = mmu_cache_alloc (state, I_CACHE (), va, pa);
223 index = va_cache_index (va, I_CACHE ());
224 *instr = cache->data[va_cache_index (va, I_CACHE ())];
225 }
226 else
227 //*instr = mem_read_word (state, pa);
228 bus_read(32, pa, instr);
229
230 return NO_FAULT;
231};
232
233
234
235static fault_t
236sa_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data)
237{
238 //ARMword temp,offset;
239 fault_t fault;
240 fault = sa_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE);
241 return fault;
242}
243
244static fault_t
245sa_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data)
246{
247 //ARMword temp,offset;
248 fault_t fault;
249 fault = sa_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE);
250 return fault;
251}
252
253static fault_t
254sa_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data)
255{
256 return sa_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);
257}
258
259
260
261
262static fault_t
263sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
264 ARMword datatype)
265{
266 fault_t fault;
267 rb_entry_t *rb;
268 tlb_entry_t *tlb;
269 cache_line_t *cache;
270 ARMword pa, real_va, temp, offset;
271
272 DEBUG_LOG(ARM11, "va = %x\n", va);
273
274 va = mmu_pid_va_map (va);
275 real_va = va;
276 /*if MMU disabled, memory_read */
277 if (MMU_Disabled) {
278 //*data = mem_read_word(state, va);
279 if (datatype == ARM_BYTE_TYPE)
280 //*data = mem_read_byte (state, va);
281 bus_read(8, va, data);
282 else if (datatype == ARM_HALFWORD_TYPE)
283 //*data = mem_read_halfword (state, va);
284 bus_read(16, va, data);
285 else if (datatype == ARM_WORD_TYPE)
286 //*data = mem_read_word (state, va);
287 bus_read(32, va, data);
288 else {
289 printf ("SKYEYE:1 sa_mmu_read error: unknown data type %d\n", datatype);
290 // skyeye_exit (-1);
291 }
292
293 return NO_FAULT;
294 }
295
296 /*align check */
297 if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
298 ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
299 DEBUG_LOG(ARM11, "align\n");
300 return ALIGNMENT_FAULT;
301 } // else
302
303 va &= ~(WORD_SIZE - 1);
304
305 /*translate va to tlb */
306 fault = translate (state, va, D_TLB (), &tlb);
307 if (fault) {
308 DEBUG_LOG(ARM11, "translate\n");
309 return fault;
310 }
311 /*check access permission */
312 fault = check_access (state, va, tlb, 1);
313 if (fault)
314 return fault;
315 /*search in read buffer */
316 rb = mmu_rb_search (RB (), va);
317 if (rb) {
318 if (rb->fault)
319 return rb->fault;
320 *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT];
321 goto datatrans;
322 //return 0;
323 };
324 /*search main cache */
325 cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
326 if (cache) {
327 *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())];
328 goto datatrans;
329 //return 0;
330 }
331 /*search mini cache */
332 cache = mmu_cache_search (state, MINI_D_CACHE (), va);
333 if (cache) {
334 *data = cache->data[va_cache_index (va, MINI_D_CACHE ())];
335 goto datatrans;
336 //return 0;
337 }
338
339 /*get phy_addr */
340 pa = tlb_va_to_pa (tlb, va);
341 if ((pa >= 0xe0000000) && (pa < 0xe8000000)) {
342 if (tlb_c_flag (tlb)) {
343 if (tlb_b_flag (tlb)) {
344 mmu_cache_soft_flush (state, MAIN_D_CACHE (),
345 pa);
346 }
347 else {
348 mmu_cache_soft_flush (state, MINI_D_CACHE (),
349 pa);
350 }
351 }
352 return NO_FAULT;
353 }
354
355 /*if Buffer, drain Write Buffer first */
356 if (tlb_b_flag (tlb))
357 mmu_wb_drain_all (state, WB ());
358
359 /*alloc cache or mem_read */
360 if (tlb_c_flag (tlb) && MMU_DCacheEnabled) {
361 cache_s *cache_t;
362
363 if (tlb_b_flag (tlb))
364 cache_t = MAIN_D_CACHE ();
365 else
366 cache_t = MINI_D_CACHE ();
367 cache = mmu_cache_alloc (state, cache_t, va, pa);
368 *data = cache->data[va_cache_index (va, cache_t)];
369 }
370 else {
371 //*data = mem_read_word(state, pa);
372 if (datatype == ARM_BYTE_TYPE)
373 //*data = mem_read_byte (state, pa | (real_va & 3));
374 bus_read(8, pa | (real_va & 3), data);
375 else if (datatype == ARM_HALFWORD_TYPE)
376 //*data = mem_read_halfword (state, pa | (real_va & 2));
377 bus_read(16, pa | (real_va & 2), data);
378 else if (datatype == ARM_WORD_TYPE)
379 //*data = mem_read_word (state, pa);
380 bus_read(32, pa, data);
381 else {
382 printf ("SKYEYE:2 sa_mmu_read error: unknown data type %d\n", datatype);
383 // skyeye_exit (-1);
384 }
385 return NO_FAULT;
386 }
387
388
389 datatrans:
390 if (datatype == ARM_HALFWORD_TYPE) {
391 temp = *data;
392 offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
393 *data = (temp >> offset) & 0xffff;
394 }
395 else if (datatype == ARM_BYTE_TYPE) {
396 temp = *data;
397 offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
398 *data = (temp >> offset & 0xffL);
399 }
400 end:
401 return NO_FAULT;
402}
403
404
405static fault_t
406sa_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data)
407{
408 return sa_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);
409}
410
411static fault_t
412sa_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data)
413{
414 return sa_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);
415}
416
417static fault_t
418sa_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data)
419{
420 return sa_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);
421}
422
423
424
425static fault_t
426sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, ARMword datatype)
427{
428 tlb_entry_t *tlb;
429 cache_line_t *cache;
430 int b;
431 ARMword pa, real_va;
432 fault_t fault;
433
434 DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data);
435 va = mmu_pid_va_map (va);
436 real_va = va;
437
438 /*search instruction cache */
439 cache = mmu_cache_search (state, I_CACHE (), va);
440 if (cache) {
441 update_cache (state, va, data, datatype, cache, I_CACHE (),
442 real_va);
443 }
444
445 if (MMU_Disabled) {
446 //mem_write_word(state, va, data);
447 if (datatype == ARM_BYTE_TYPE)
448 //mem_write_byte (state, va, data);
449 bus_write(8, va, data);
450 else if (datatype == ARM_HALFWORD_TYPE)
451 //mem_write_halfword (state, va, data);
452 bus_write(16, va, data);
453 else if (datatype == ARM_WORD_TYPE)
454 //mem_write_word (state, va, data);
455 bus_write(32, va, data);
456 else {
457 printf ("SKYEYE:1 sa_mmu_write error: unknown data type %d\n", datatype);
458 // skyeye_exit (-1);
459 }
460
461 return NO_FAULT;
462 }
463 /*align check */
464 //if ((va & (WORD_SIZE - 1)) && MMU_Aligned){
465 if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
466 ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
467 DEBUG_LOG(ARM11, "align\n");
468 return ALIGNMENT_FAULT;
469 } //else
470 va &= ~(WORD_SIZE - 1);
471 /*tlb translate */
472 fault = translate (state, va, D_TLB (), &tlb);
473 if (fault) {
474 DEBUG_LOG(ARM11, "translate\n");
475 return fault;
476 }
477 /*tlb check access */
478 fault = check_access (state, va, tlb, 0);
479 if (fault) {
480 DEBUG_LOG(ARM11, "check_access\n");
481 return fault;
482 }
483 /*search main cache */
484 cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
485 if (cache) {
486 update_cache (state, va, data, datatype, cache,
487 MAIN_D_CACHE (), real_va);
488 }
489 else {
490 /*search mini cache */
491 cache = mmu_cache_search (state, MINI_D_CACHE (), va);
492 if (cache) {
493 update_cache (state, va, data, datatype, cache,
494 MINI_D_CACHE (), real_va);
495 }
496 }
497
498 if (!cache) {
499 b = tlb_b_flag (tlb);
500 pa = tlb_va_to_pa (tlb, va);
501 if (b) {
502 if (MMU_WBEnabled) {
503 if (datatype == ARM_WORD_TYPE)
504 mmu_wb_write_bytes (state, WB (), pa,
505 (ARMbyte*)&data, 4);
506 else if (datatype == ARM_HALFWORD_TYPE)
507 mmu_wb_write_bytes (state, WB (),
508 (pa |
509 (real_va & 2)),
510 (ARMbyte*)&data, 2);
511 else if (datatype == ARM_BYTE_TYPE)
512 mmu_wb_write_bytes (state, WB (),
513 (pa |
514 (real_va & 3)),
515 (ARMbyte*)&data, 1);
516
517 }
518 else {
519 if (datatype == ARM_WORD_TYPE)
520 //mem_write_word (state, pa, data);
521 bus_write(32, pa, data);
522 else if (datatype == ARM_HALFWORD_TYPE)
523 /*
524 mem_write_halfword (state,
525 (pa |
526 (real_va & 2)),
527 data);
528 */
529 bus_write(16, pa | (real_va & 2), data);
530 else if (datatype == ARM_BYTE_TYPE)
531 /*
532 mem_write_byte (state,
533 (pa | (real_va & 3)),
534 data);
535 */
536 bus_write(8, pa | (real_va & 3), data);
537 }
538 }
539 else {
540 mmu_wb_drain_all (state, WB ());
541
542 if (datatype == ARM_WORD_TYPE)
543 //mem_write_word (state, pa, data);
544 bus_write(32, pa, data);
545 else if (datatype == ARM_HALFWORD_TYPE)
546 /*
547 mem_write_halfword (state,
548 (pa | (real_va & 2)),
549 data);
550 */
551 bus_write(16, pa | (real_va & 2), data);
552 else if (datatype == ARM_BYTE_TYPE)
553 /*
554 mem_write_byte (state, (pa | (real_va & 3)),
555 data);
556 */
557 bus_write(8, pa | (real_va & 3), data);
558 }
559 }
560 return NO_FAULT;
561}
562
563static fault_t
564update_cache (ARMul_State * state, ARMword va, ARMword data, ARMword datatype,
565 cache_line_t * cache, cache_s * cache_t, ARMword real_va)
566{
567 ARMword temp, offset;
568
569 ARMword index = va_cache_index (va, cache_t);
570
571 //cache->data[index] = data;
572
573 if (datatype == ARM_WORD_TYPE)
574 cache->data[index] = data;
575 else if (datatype == ARM_HALFWORD_TYPE) {
576 temp = cache->data[index];
577 offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
578 cache->data[index] =
579 (temp & ~(0xffffL << offset)) | ((data & 0xffffL) <<
580 offset);
581 }
582 else if (datatype == ARM_BYTE_TYPE) {
583 temp = cache->data[index];
584 offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
585 cache->data[index] =
586 (temp & ~(0xffL << offset)) | ((data & 0xffL) <<
587 offset);
588 }
589
590 if (index < (cache_t->width >> (WORD_SHT + 1)))
591 cache->tag |= TAG_FIRST_HALF_DIRTY;
592 else
593 cache->tag |= TAG_LAST_HALF_DIRTY;
594
595 return NO_FAULT;
596}
597
598ARMword
599sa_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value)
600{
601 mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15);
602 ARMword data;
603
604 switch (creg) {
605 case MMU_ID:
606// printf("mmu_mrc read ID ");
607 data = 0x41007100; /* v3 */
608 data = state->cpu->cpu_val;
609 break;
610 case MMU_CONTROL:
611// printf("mmu_mrc read CONTROL");
612 data = state->mmu.control;
613 break;
614 case MMU_TRANSLATION_TABLE_BASE:
615// printf("mmu_mrc read TTB ");
616 data = state->mmu.translation_table_base;
617 break;
618 case MMU_DOMAIN_ACCESS_CONTROL:
619// printf("mmu_mrc read DACR ");
620 data = state->mmu.domain_access_control;
621 break;
622 case MMU_FAULT_STATUS:
623// printf("mmu_mrc read FSR ");
624 data = state->mmu.fault_status;
625 break;
626 case MMU_FAULT_ADDRESS:
627// printf("mmu_mrc read FAR ");
628 data = state->mmu.fault_address;
629 break;
630 case MMU_PID:
631 data = state->mmu.process_id;
632 default:
633 printf ("mmu_mrc read UNKNOWN - reg %d\n", creg);
634 data = 0;
635 break;
636 }
637// printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]);
638 *value = data;
639 return data;
640}
641
642void
643sa_mmu_cache_ops (ARMul_State * state, ARMword instr, ARMword value)
644{
645 int CRm, OPC_2;
646
647 CRm = BITS (0, 3);
648 OPC_2 = BITS (5, 7);
649
650 if (OPC_2 == 0 && CRm == 7) {
651 mmu_cache_invalidate_all (state, I_CACHE ());
652 mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
653 mmu_cache_invalidate_all (state, MINI_D_CACHE ());
654 return;
655 }
656
657 if (OPC_2 == 0 && CRm == 5) {
658 mmu_cache_invalidate_all (state, I_CACHE ());
659 return;
660 }
661
662 if (OPC_2 == 0 && CRm == 6) {
663 mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
664 mmu_cache_invalidate_all (state, MINI_D_CACHE ());
665 return;
666 }
667
668 if (OPC_2 == 1 && CRm == 6) {
669 mmu_cache_invalidate (state, MAIN_D_CACHE (), value);
670 mmu_cache_invalidate (state, MINI_D_CACHE (), value);
671 return;
672 }
673
674 if (OPC_2 == 1 && CRm == 0xa) {
675 mmu_cache_clean (state, MAIN_D_CACHE (), value);
676 mmu_cache_clean (state, MINI_D_CACHE (), value);
677 return;
678 }
679
680 if (OPC_2 == 4 && CRm == 0xa) {
681 mmu_wb_drain_all (state, WB ());
682 return;
683 }
684 ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
685}
686
687static void
688sa_mmu_tlb_ops (ARMul_State * state, ARMword instr, ARMword value)
689{
690 int CRm, OPC_2;
691
692 CRm = BITS (0, 3);
693 OPC_2 = BITS (5, 7);
694
695
696 if (OPC_2 == 0 && CRm == 0x7) {
697 mmu_tlb_invalidate_all (state, I_TLB ());
698 mmu_tlb_invalidate_all (state, D_TLB ());
699 return;
700 }
701
702 if (OPC_2 == 0 && CRm == 0x5) {
703 mmu_tlb_invalidate_all (state, I_TLB ());
704 return;
705 }
706
707 if (OPC_2 == 0 && CRm == 0x6) {
708 mmu_tlb_invalidate_all (state, D_TLB ());
709 return;
710 }
711
712 if (OPC_2 == 1 && CRm == 0x6) {
713 mmu_tlb_invalidate_entry (state, D_TLB (), value);
714 return;
715 }
716
717 ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
718}
719
720static void
721sa_mmu_rb_ops (ARMul_State * state, ARMword instr, ARMword value)
722{
723 int CRm, OPC_2;
724
725 CRm = BITS (0, 3);
726 OPC_2 = BITS (5, 7);
727
728 if (OPC_2 == 0x0 && CRm == 0x0) {
729 mmu_rb_invalidate_all (RB ());
730 return;
731 }
732
733 if (OPC_2 == 0x2) {
734 int idx = CRm & 0x3;
735 int type = ((CRm >> 2) & 0x3) + 1;
736
737 if ((idx < 4) && (type < 4))
738 mmu_rb_load (state, RB (), idx, type, value);
739 return;
740 }
741
742 if ((OPC_2 == 1) && (CRm < 4)) {
743 mmu_rb_invalidate_entry (RB (), CRm);
744 return;
745 }
746
747 ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm);
748}
749
750static ARMword
751sa_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value)
752{
753 mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15);
754 if (!strncmp (state->cpu->cpu_arch_name, "armv4", 5)) {
755 switch (creg) {
756 case MMU_CONTROL:
757// printf("mmu_mcr wrote CONTROL ");
758 state->mmu.control = (value | 0x70) & 0xFFFD;
759 break;
760 case MMU_TRANSLATION_TABLE_BASE:
761// printf("mmu_mcr wrote TTB ");
762 state->mmu.translation_table_base =
763 value & 0xFFFFC000;
764 break;
765 case MMU_DOMAIN_ACCESS_CONTROL:
766// printf("mmu_mcr wrote DACR ");
767 state->mmu.domain_access_control = value;
768 break;
769
770 case MMU_FAULT_STATUS:
771 state->mmu.fault_status = value & 0xFF;
772 break;
773 case MMU_FAULT_ADDRESS:
774 state->mmu.fault_address = value;
775 break;
776
777 case MMU_CACHE_OPS:
778 sa_mmu_cache_ops (state, instr, value);
779 break;
780 case MMU_TLB_OPS:
781 sa_mmu_tlb_ops (state, instr, value);
782 break;
783 case MMU_SA_RB_OPS:
784 sa_mmu_rb_ops (state, instr, value);
785 break;
786 case MMU_SA_DEBUG:
787 break;
788 case MMU_SA_CP15_R15:
789 break;
790 case MMU_PID:
791 //2004-06-06 lyh, bug provided by wen ye wenye@cs.ucsb.edu
792 state->mmu.process_id = value & 0x7e000000;
793 break;
794
795 default:
796 printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg);
797 break;
798 }
799 }
800 return 0;
801}
802
803//teawater add for arm2x86 2005.06.24-------------------------------------------
804static int
805sa_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr)
806{
807 fault_t fault;
808 tlb_entry_t *tlb;
809
810 virt_addr = mmu_pid_va_map (virt_addr);
811 if (MMU_Enabled) {
812
813 /*align check */
814 if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) {
815 DEBUG_LOG(ARM11, "align\n");
816 return ALIGNMENT_FAULT;
817 }
818 else
819 virt_addr &= ~(WORD_SIZE - 1);
820
821 /*translate tlb */
822 fault = translate (state, virt_addr, I_TLB (), &tlb);
823 if (fault) {
824 DEBUG_LOG(ARM11, "translate\n");
825 return fault;
826 }
827
828 /*check access */
829 fault = check_access (state, virt_addr, tlb, 1);
830 if (fault) {
831 DEBUG_LOG(ARM11, "check_fault\n");
832 return fault;
833 }
834 }
835
836 if (MMU_Disabled) {
837 *phys_addr = virt_addr;
838 }
839 else {
840 *phys_addr = tlb_va_to_pa (tlb, virt_addr);
841 }
842
843 return (0);
844}
845
846//AJ2D--------------------------------------------------------------------------
847
848/*sa mmu_ops_t*/
849mmu_ops_t sa_mmu_ops = {
850 sa_mmu_init,
851 sa_mmu_exit,
852 sa_mmu_read_byte,
853 sa_mmu_write_byte,
854 sa_mmu_read_halfword,
855 sa_mmu_write_halfword,
856 sa_mmu_read_word,
857 sa_mmu_write_word,
858 sa_mmu_load_instr,
859 sa_mmu_mcr,
860 sa_mmu_mrc,
861//teawater add for arm2x86 2005.06.24-------------------------------------------
862 sa_mmu_v2p_dbct,
863//AJ2D--------------------------------------------------------------------------
864};
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 @@
1/*
2 sa_mmu.h - StrongARM Memory Management Unit emulation.
3 ARMulator extensions for SkyEye.
4 <lyhost@263.net>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#ifndef _SA_MMU_H_
22#define _SA_MMU_H_
23
24
25/**
26 * The interface of read data from bus
27 */
28int bus_read(short size, int addr, uint32_t * value);
29
30/**
31 * The interface of write data from bus
32 */
33int bus_write(short size, int addr, uint32_t value);
34
35
36typedef struct sa_mmu_s
37{
38 tlb_s i_tlb;
39 cache_s i_cache;
40
41 tlb_s d_tlb;
42 cache_s main_d_cache;
43 cache_s mini_d_cache;
44 rb_s rb_t;
45 wb_s wb_t;
46} sa_mmu_t;
47
48#define I_TLB() (&state->mmu.u.sa_mmu.i_tlb)
49#define I_CACHE() (&state->mmu.u.sa_mmu.i_cache)
50
51#define D_TLB() (&state->mmu.u.sa_mmu.d_tlb)
52#define MAIN_D_CACHE() (&state->mmu.u.sa_mmu.main_d_cache)
53#define MINI_D_CACHE() (&state->mmu.u.sa_mmu.mini_d_cache)
54#define WB() (&state->mmu.u.sa_mmu.wb_t)
55#define RB() (&state->mmu.u.sa_mmu.rb_t)
56
57extern mmu_ops_t sa_mmu_ops;
58#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 @@
1#include <assert.h>
2
3#include "core/arm/interpreter/armdefs.h"
4
5ARMword tlb_masks[] = {
6 0x00000000, /* TLB_INVALID */
7 0xFFFFF000, /* TLB_SMALLPAGE */
8 0xFFFF0000, /* TLB_LARGEPAGE */
9 0xFFF00000, /* TLB_SECTION */
10 0xFFFFF000, /*TLB_ESMALLPAGE, have TEX attirbute, only for XScale */
11 0xFFFFFC00 /* TLB_TINYPAGE */
12};
13
14/* This function encodes table 8-2 Interpreting AP bits,
15 returning non-zero if access is allowed. */
16static int
17check_perms (ARMul_State * state, int ap, int read)
18{
19 int s, r, user;
20
21 s = state->mmu.control & CONTROL_SYSTEM;
22 r = state->mmu.control & CONTROL_ROM;
23 //chy 2006-02-15 , should consider system mode, don't conside 26bit mode
24 user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE);
25
26 switch (ap) {
27 case 0:
28 return read && ((s && !user) || r);
29 case 1:
30 return !user;
31 case 2:
32 return read || !user;
33 case 3:
34 return 1;
35 }
36 return 0;
37}
38
39fault_t
40check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb,
41 int read)
42{
43 int access;
44
45 state->mmu.last_domain = tlb->domain;
46 access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3;
47 if ((access == 0) || (access == 2)) {
48 /* It's unclear from the documentation whether this
49 should always raise a section domain fault, or if
50 it should be a page domain fault in the case of an
51 L1 that describes a page table. In the ARM710T
52 datasheets, "Figure 8-9: Sequence for checking faults"
53 seems to indicate the former, while "Table 8-4: Priority
54 encoding of fault status" gives a value for FS[3210] in
55 the event of a domain fault for a page. Hmm. */
56 return SECTION_DOMAIN_FAULT;
57 }
58 if (access == 1) {
59 /* client access - check perms */
60 int subpage, ap;
61
62 switch (tlb->mapping) {
63 /*ks 2004-05-09
64 * only for XScale
65 * Extend Small Page(ESP) Format
66 * 31-12 bits the base addr of ESP
67 * 11-10 bits SBZ
68 * 9-6 bits TEX
69 * 5-4 bits AP
70 * 3 bit C
71 * 2 bit B
72 * 1-0 bits 11
73 * */
74 case TLB_ESMALLPAGE: //xj
75 subpage = 0;
76 //printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr );
77 break;
78
79 case TLB_TINYPAGE:
80 subpage = 0;
81 //printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr );
82 break;
83
84 case TLB_SMALLPAGE:
85 subpage = (virt_addr >> 10) & 3;
86 break;
87 case TLB_LARGEPAGE:
88 subpage = (virt_addr >> 14) & 3;
89 break;
90 case TLB_SECTION:
91 subpage = 3;
92 break;
93 default:
94 assert (0);
95 subpage = 0; /* cleans a warning */
96 }
97 ap = (tlb->perms >> (subpage * 2 + 4)) & 3;
98 if (!check_perms (state, ap, read)) {
99 if (tlb->mapping == TLB_SECTION) {
100 return SECTION_PERMISSION_FAULT;
101 }
102 else {
103 return SUBPAGE_PERMISSION_FAULT;
104 }
105 }
106 }
107 else { /* access == 3 */
108 /* manager access - don't check perms */
109 }
110 return NO_FAULT;
111}
112
113fault_t
114translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t,
115 tlb_entry_t ** tlb)
116{
117 *tlb = mmu_tlb_search (state, tlb_t, virt_addr);
118 if (!*tlb) {
119 /* walk the translation tables */
120 ARMword l1addr, l1desc;
121 tlb_entry_t entry;
122
123 l1addr = state->mmu.translation_table_base & 0xFFFFC000;
124 l1addr = (l1addr | (virt_addr >> 18)) & ~3;
125 //l1desc = mem_read_word (state, l1addr);
126 bus_read(32, l1addr, &l1desc);
127 switch (l1desc & 3) {
128 case 0:
129 /*
130 * according to Figure 3-9 Sequence for checking faults in arm manual,
131 * section translation fault should be returned here.
132 */
133 {
134 return SECTION_TRANSLATION_FAULT;
135 }
136 case 3:
137 /* fine page table */
138 // dcl 2006-01-08
139 {
140 ARMword l2addr, l2desc;
141
142 l2addr = l1desc & 0xFFFFF000;
143 l2addr = (l2addr |
144 ((virt_addr & 0x000FFC00) >> 8)) &
145 ~3;
146 //l2desc = mem_read_word (state, l2addr);
147 bus_read(32, l2addr, &l2desc);
148
149 entry.virt_addr = virt_addr;
150 entry.phys_addr = l2desc;
151 entry.perms = l2desc & 0x00000FFC;
152 entry.domain = (l1desc >> 5) & 0x0000000F;
153 switch (l2desc & 3) {
154 case 0:
155 state->mmu.last_domain = entry.domain;
156 return PAGE_TRANSLATION_FAULT;
157 case 3:
158 entry.mapping = TLB_TINYPAGE;
159 break;
160 case 1:
161 // this is untested
162 entry.mapping = TLB_LARGEPAGE;
163 break;
164 case 2:
165 // this is untested
166 entry.mapping = TLB_SMALLPAGE;
167 break;
168 }
169 }
170 break;
171 case 1:
172 /* coarse page table */
173 {
174 ARMword l2addr, l2desc;
175
176 l2addr = l1desc & 0xFFFFFC00;
177 l2addr = (l2addr |
178 ((virt_addr & 0x000FF000) >> 10)) &
179 ~3;
180 //l2desc = mem_read_word (state, l2addr);
181 bus_read(32, l2addr, &l2desc);
182
183 entry.virt_addr = virt_addr;
184 entry.phys_addr = l2desc;
185 entry.perms = l2desc & 0x00000FFC;
186 entry.domain = (l1desc >> 5) & 0x0000000F;
187 //printf("SKYEYE:PAGE virt_addr = %x,l1desc=%x,phys_addr=%x\n",virt_addr,l1desc,entry.phys_addr);
188 //chy 2003-09-02 for xscale
189 switch (l2desc & 3) {
190 case 0:
191 state->mmu.last_domain = entry.domain;
192 return PAGE_TRANSLATION_FAULT;
193 case 3:
194 if (!state->is_XScale) {
195 state->mmu.last_domain =
196 entry.domain;
197 return PAGE_TRANSLATION_FAULT;
198 };
199 //ks 2004-05-09 xscale shold use Extend Small Page
200 //entry.mapping = TLB_SMALLPAGE;
201 entry.mapping = TLB_ESMALLPAGE; //xj
202 break;
203 case 1:
204 entry.mapping = TLB_LARGEPAGE;
205 break;
206 case 2:
207 entry.mapping = TLB_SMALLPAGE;
208 break;
209 }
210 }
211 break;
212 case 2:
213 /* section */
214 //printf("SKYEYE:WARNING: not implement section mapping incompletely\n");
215 //printf("SKYEYE:SECTION virt_addr = %x,l1desc=%x\n",virt_addr,l1desc);
216 //return SECTION_DOMAIN_FAULT;
217 //#if 0
218 entry.virt_addr = virt_addr;
219 entry.phys_addr = l1desc;
220 entry.perms = l1desc & 0x00000C0C;
221 entry.domain = (l1desc >> 5) & 0x0000000F;
222 entry.mapping = TLB_SECTION;
223 break;
224 //#endif
225 }
226 entry.virt_addr &= tlb_masks[entry.mapping];
227 entry.phys_addr &= tlb_masks[entry.mapping];
228
229 /* place entry in the tlb */
230 *tlb = &tlb_t->entrys[tlb_t->cycle];
231 tlb_t->cycle = (tlb_t->cycle + 1) % tlb_t->num;
232 **tlb = entry;
233 }
234 state->mmu.last_domain = (*tlb)->domain;
235 return NO_FAULT;
236}
237
238int
239mmu_tlb_init (tlb_s * tlb_t, int num)
240{
241 tlb_entry_t *e;
242 int i;
243
244 e = (tlb_entry_t *) malloc (sizeof (*e) * num);
245 if (e == NULL) {
246 ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*e) * num);
247 goto tlb_malloc_error;
248 }
249 tlb_t->entrys = e;
250 for (i = 0; i < num; i++, e++)
251 e->mapping = TLB_INVALID;
252 tlb_t->cycle = 0;
253 tlb_t->num = num;
254 return 0;
255
256 tlb_malloc_error:
257 return -1;
258}
259
260void
261mmu_tlb_exit (tlb_s * tlb_t)
262{
263 free (tlb_t->entrys);
264};
265
266void
267mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t)
268{
269 int entry;
270
271 for (entry = 0; entry < tlb_t->num; entry++) {
272 tlb_t->entrys[entry].mapping = TLB_INVALID;
273 }
274 tlb_t->cycle = 0;
275}
276
277void
278mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr)
279{
280 tlb_entry_t *tlb;
281
282 tlb = mmu_tlb_search (state, tlb_t, addr);
283 if (tlb) {
284 tlb->mapping = TLB_INVALID;
285 }
286}
287
288tlb_entry_t *
289mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, ARMword virt_addr)
290{
291 int entry;
292
293 for (entry = 0; entry < tlb_t->num; entry++) {
294 tlb_entry_t *tlb;
295 ARMword mask;
296
297 tlb = &(tlb_t->entrys[entry]);
298 if (tlb->mapping == TLB_INVALID) {
299 continue;
300 }
301 mask = tlb_masks[tlb->mapping];
302 if ((virt_addr & mask) == (tlb->virt_addr & mask)) {
303 return tlb;
304 }
305 }
306 return NULL;
307}
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 @@
1#ifndef _MMU_TLB_H_
2#define _MMU_TLB_H_
3
4typedef enum tlb_mapping_t
5{
6 TLB_INVALID = 0,
7 TLB_SMALLPAGE = 1,
8 TLB_LARGEPAGE = 2,
9 TLB_SECTION = 3,
10 TLB_ESMALLPAGE = 4,
11 TLB_TINYPAGE = 5
12} tlb_mapping_t;
13
14extern ARMword tlb_masks[];
15
16/* Permissions bits in a TLB entry:
17 *
18 * 31 12 11 10 9 8 7 6 5 4 3 2 1 0
19 * +-------------+-----+-----+-----+-----+---+---+-------+
20 * Page:| | ap3 | ap2 | ap1 | ap0 | C | B | |
21 * +-------------+-----+-----+-----+-----+---+---+-------+
22 *
23 * 31 12 11 10 9 4 3 2 1 0
24 * +-------------+-----+-----------------+---+---+-------+
25 * Section: | | AP | | C | B | |
26 * +-------------+-----+-----------------+---+---+-------+
27 */
28
29/*
30section:
31 section base address [31:20]
32 AP - table 8-2, page 8-8
33 domain
34 C,B
35
36page:
37 page base address [31:16] or [31:12]
38 ap[3:0]
39 domain (from L1)
40 C,B
41*/
42
43
44typedef struct tlb_entry_t
45{
46 ARMword virt_addr;
47 ARMword phys_addr;
48 ARMword perms;
49 ARMword domain;
50 tlb_mapping_t mapping;
51} tlb_entry_t;
52
53typedef struct tlb_s
54{
55 int num; /*num of tlb entry */
56 int cycle; /*current tlb cycle */
57 tlb_entry_t *entrys;
58} tlb_s;
59
60
61#define tlb_c_flag(tlb) \
62 ((tlb)->perms & 0x8)
63#define tlb_b_flag(tlb) \
64 ((tlb)->perms & 0x4)
65
66#define tlb_va_to_pa(tlb, va) ((tlb->phys_addr & tlb_masks[tlb->mapping]) | (va & ~tlb_masks[tlb->mapping]))
67fault_t
68check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb,
69 int read);
70
71fault_t
72translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t,
73 tlb_entry_t ** tlb);
74
75int mmu_tlb_init (tlb_s * tlb_t, int num);
76
77void mmu_tlb_exit (tlb_s * tlb_t);
78
79void mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t);
80
81void
82mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr);
83
84tlb_entry_t *mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t,
85 ARMword virt_addr);
86
87#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 @@
1#include "core/arm/interpreter/armdefs.h"
2
3/* wb_init
4 * @wb_t :wb_t to init
5 * @num :num of entrys
6 * @nb :num of byte of each entry
7 *
8 * $ -1:error
9 * 0:ok
10 * */
11int
12mmu_wb_init (wb_s * wb_t, int num, int nb)
13{
14 int i;
15 wb_entry_t *entrys, *wb;
16
17 entrys = (wb_entry_t *) malloc (sizeof (*entrys) * num);
18 if (entrys == NULL) {
19 ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*entrys) * num);
20 goto entrys_malloc_error;
21 }
22
23 for (wb = entrys, i = 0; i < num; i++, wb++) {
24 /*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu */
25 //wb->data = (ARMword *)malloc(sizeof(ARMword) * nb);
26 wb->data = (ARMbyte *) malloc (nb);
27 if (wb->data == NULL) {
28 ERROR_LOG(ARM11, "malloc size of %d\n", nb);
29 goto data_malloc_error;
30 }
31
32 };
33
34 wb_t->first = wb_t->last = wb_t->used = 0;
35 wb_t->num = num;
36 wb_t->nb = nb;
37 wb_t->entrys = entrys;
38 return 0;
39
40 data_malloc_error:
41 while (--i >= 0)
42 free (entrys[i].data);
43 free (entrys);
44 entrys_malloc_error:
45 return -1;
46};
47
48/* wb_exit
49 * @wb_t :wb_t to exit
50 * */
51void
52mmu_wb_exit (wb_s * wb_t)
53{
54 int i;
55 wb_entry_t *wb;
56
57 wb = wb_t->entrys;
58 for (i = 0; i < wb_t->num; i++, wb++) {
59 free (wb->data);
60 }
61 free (wb_t->entrys);
62};
63
64/* wb_write_words :put words in Write Buffer
65 * @state: ARMul_State
66 * @wb_t: write buffer
67 * @pa: physical address
68 * @data: data ptr
69 * @n number of word to write
70 *
71 * Note: write buffer merge is not implemented, can be done late
72 * */
73void
74mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa,
75 ARMbyte * data, int n)
76{
77 int i;
78 wb_entry_t *wb;
79
80 while (n) {
81 if (wb_t->num == wb_t->used) {
82 /*clean the last wb entry */
83 ARMword t;
84
85 wb = &wb_t->entrys[wb_t->last];
86 t = wb->pa;
87 for (i = 0; i < wb->nb; i++) {
88 //mem_write_byte (state, t, wb->data[i]);
89 bus_write(8, t, wb->data[i]);
90 //t += WORD_SIZE;
91 t++;
92 }
93 wb_t->last++;
94 if (wb_t->last == wb_t->num)
95 wb_t->last = 0;
96 wb_t->used--;
97 }
98
99 wb = &wb_t->entrys[wb_t->first];
100 i = (n < wb_t->nb) ? n : wb_t->nb;
101
102 wb->pa = pa;
103 //pa += i << WORD_SHT;
104 pa += i;
105
106 wb->nb = i;
107 //memcpy(wb->data, data, i << WORD_SHT);
108 memcpy (wb->data, data, i);
109 data += i;
110 n -= i;
111 wb_t->first++;
112 if (wb_t->first == wb_t->num)
113 wb_t->first = 0;
114 wb_t->used++;
115 };
116//teawater add for set_dirty fflash cache function 2005.07.18-------------------
117#ifdef DBCT
118 if (!skyeye_config.no_dbct) {
119 tb_setdirty (state, pa, NULL);
120 }
121#endif
122//AJ2D--------------------------------------------------------------------------
123}
124
125/* wb_drain_all
126 * @wb_t wb_t to drain
127 * */
128void
129mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t)
130{
131 ARMword pa;
132 wb_entry_t *wb;
133 int i;
134
135 while (wb_t->used) {
136 wb = &wb_t->entrys[wb_t->last];
137 pa = wb->pa;
138 for (i = 0; i < wb->nb; i++) {
139 //mem_write_byte (state, pa, wb->data[i]);
140 bus_write(8, pa, wb->data[i]);
141 //pa += WORD_SIZE;
142 pa++;
143 }
144 wb_t->last++;
145 if (wb_t->last == wb_t->num)
146 wb_t->last = 0;
147 wb_t->used--;
148 };
149}
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 @@
1#ifndef _MMU_WB_H_
2#define _MMU_WB_H_
3
4typedef struct wb_entry_s
5{
6 ARMword pa; //phy_addr
7 ARMbyte *data; //data
8 int nb; //number byte to write
9} wb_entry_t;
10
11typedef struct wb_s
12{
13 int num; //number of wb_entry
14 int nb; //number of byte of each entry
15 int first; //
16 int last; //
17 int used; //
18 wb_entry_t *entrys;
19} wb_s;
20
21typedef struct wb_desc_s
22{
23 int num;
24 int nb;
25} wb_desc_t;
26
27/* wb_init
28 * @wb_t :wb_t to init
29 * @num :num of entrys
30 * @nw :num of word of each entry
31 *
32 * $ -1:error
33 * 0:ok
34 * */
35int mmu_wb_init (wb_s * wb_t, int num, int nb);
36
37
38/* wb_exit
39 * @wb_t :wb_t to exit
40 * */
41void mmu_wb_exit (wb_s * wb);
42
43
44/* wb_write_bytes :put bytess in Write Buffer
45 * @state: ARMul_State
46 * @wb_t: write buffer
47 * @pa: physical address
48 * @data: data ptr
49 * @n number of byte to write
50 *
51 * Note: write buffer merge is not implemented, can be done late
52 * */
53void
54mmu_wb_write_bytess (ARMul_State * state, wb_s * wb_t, ARMword pa,
55 ARMbyte * data, int n);
56
57
58/* wb_drain_all
59 * @wb_t wb_t to drain
60 * */
61void mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t);
62
63#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 @@
1/*
2 armmmu.c - Memory Management Unit emulation.
3 ARMulator extensions for the ARM7100 family.
4 Copyright (C) 1999 Ben Williamson
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#include <assert.h>
22#include <string.h>
23
24#include "core/arm/interpreter/armdefs.h"
25#include "core/arm/interpreter/armemu.h"
26
27/*#include "pxa.h" */
28
29/* chy 2005-09-19 */
30
31/* extern pxa270_io_t pxa270_io; */
32/* chy 2005-09-19 -----end */
33
34typedef struct xscale_mmu_desc_s
35{
36 int i_tlb;
37 cache_desc_t i_cache;
38
39 int d_tlb;
40 cache_desc_t main_d_cache;
41 cache_desc_t mini_d_cache;
42 //int rb; xscale has no read buffer
43 wb_desc_t wb;
44} xscale_mmu_desc_t;
45
46static xscale_mmu_desc_t pxa_mmu_desc = {
47 32,
48 {32, 32, 32, CACHE_WRITE_BACK},
49
50 32,
51 {32, 32, 32, CACHE_WRITE_BACK},
52 {32, 2, 8, CACHE_WRITE_BACK},
53 {8, 16}, //for byte size,
54};
55
56//chy 2005-09-19 for cp6
57#define CR0_ICIP 0
58#define CR1_ICMR 1
59//chy 2005-09-19 ---end
60//----------- for cp14-----------------
61#define CCLKCFG 6
62#define PWRMODE 7
63typedef struct xscale_cp14_reg_s
64{
65 unsigned cclkcfg; //reg6
66 unsigned pwrmode; //reg7
67} xscale_cp14_reg_s;
68
69xscale_cp14_reg_s pxa_cp14_regs;
70
71//--------------------------------------
72
73static fault_t xscale_mmu_write (ARMul_State * state, ARMword va,
74 ARMword data, ARMword datatype);
75static fault_t xscale_mmu_read (ARMul_State * state, ARMword va,
76 ARMword * data, ARMword datatype);
77
78ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value);
79ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value);
80
81
82/* jeff add 2010.9.26 for pxa270 cp6*/
83#define PXA270_ICMR 0x40D00004
84#define PXA270_ICPR 0x40D00010
85#define PXA270_ICLR 0x40D00008
86//chy 2005-09-19 for xscale pxa27x cp6
87unsigned
88xscale_cp6_mrc (ARMul_State * state, unsigned type, ARMword instr,
89 ARMword * data)
90{
91 unsigned opcode_2 = BITS (5, 7);
92 unsigned CRm = BITS (0, 3);
93 unsigned reg = BITS (16, 19);
94 unsigned result;
95
96 //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);
97
98 switch (reg) {
99 case CR0_ICIP: { // cp 6 reg 0
100 //printf("cp6_mrc cr0 ICIP \n");
101 /* *data = (pxa270_io.icmr & pxa270_io.icpr) & ~pxa270_io.iclr; */
102 /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/
103 int icmr, icpr, iclr;
104 bus_read(32, PXA270_ICMR, (uint32_t*)&icmr);
105 bus_read(32, PXA270_ICPR, (uint32_t*)&icpr);
106 bus_read(32, PXA270_ICLR, (uint32_t*)&iclr);
107 *data = (icmr & icpr) & ~iclr;
108 }
109 break;
110 case CR1_ICMR: { // cp 6 reg 1
111 //printf("cp6_mrc cr1 ICMR\n");
112 /* *data = pxa270_io.icmr; */
113 int icmr;
114 /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/
115 bus_read(32, PXA270_ICMR, (uint32_t*)&icmr);
116 *data = icmr;
117 }
118 break;
119 default:
120 *data = 0;
121 printf ("SKYEYE:cp6_mrc unknown cp6 regs!!!!!!\n");
122 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);
123 break;
124 }
125 return 0;
126}
127
128//chy 2005-09-19 end
129//xscale cp13 ----------------------------------------------------
130unsigned
131xscale_cp13_init (ARMul_State * state)
132{
133 //printf("SKYEYE: xscale_cp13_init: begin\n");
134 return 0;
135}
136
137unsigned
138xscale_cp13_exit (ARMul_State * state)
139{
140 //printf("SKYEYE: xscale_cp13_exit: begin\n");
141 return 0;
142}
143
144unsigned
145xscale_cp13_ldc (ARMul_State * state, unsigned type, ARMword instr,
146 ARMword data)
147{
148 printf ("SKYEYE: xscale_cp13_ldc: ERROR isn't existed,");
149 SKYEYE_OUTREGS (stderr);
150 fprintf (stderr, "\n");
151 // skyeye_exit (-1);
152 return 0; //No matter return value, only for compiler.
153}
154
155unsigned
156xscale_cp13_stc (ARMul_State * state, unsigned type, ARMword instr,
157 ARMword * data)
158{
159 printf ("SKYEYE: xscale_cp13_stc: ERROR isn't existed,");
160 SKYEYE_OUTREGS (stderr);
161 fprintf (stderr, "\n");
162 // skyeye_exit (-1);
163 return 0; //No matter return value, only for compiler.
164}
165
166unsigned
167xscale_cp13_mrc (ARMul_State * state, unsigned type, ARMword instr,
168 ARMword * data)
169{
170 printf ("SKYEYE: xscale_cp13_mrc: ERROR isn't existed,");
171 SKYEYE_OUTREGS (stderr);
172 fprintf (stderr, "\n");
173 // skyeye_exit (-1);
174 return 0; //No matter return value, only for compiler.
175}
176
177unsigned
178xscale_cp13_mcr (ARMul_State * state, unsigned type, ARMword instr,
179 ARMword data)
180{
181 printf ("SKYEYE: xscale_cp13_mcr: ERROR isn't existed,");
182 SKYEYE_OUTREGS (stderr);
183 fprintf (stderr, "\n");
184 // skyeye_exit (-1);
185 return 0; //No matter return value, only for compiler.
186}
187
188unsigned
189xscale_cp13_cdp (ARMul_State * state, unsigned type, ARMword instr)
190{
191 printf ("SKYEYE: xscale_cp13_cdp: ERROR isn't existed,");
192 SKYEYE_OUTREGS (stderr);
193 fprintf (stderr, "\n");
194 // skyeye_exit (-1);
195 return 0; //No matter return value, only for compiler.
196}
197
198unsigned
199xscale_cp13_read_reg (ARMul_State * state, unsigned reg, ARMword * data)
200{
201 printf ("SKYEYE: xscale_cp13_read_reg: ERROR isn't existed,");
202 SKYEYE_OUTREGS (stderr);
203 fprintf (stderr, "\n");
204 return 0;
205 //exit(-1);
206}
207
208unsigned
209xscale_cp13_write_reg (ARMul_State * state, unsigned reg, ARMword data)
210{
211 printf ("SKYEYE: xscale_cp13_write_reg: ERROR isn't existed,");
212 SKYEYE_OUTREGS (stderr);
213 fprintf (stderr, "\n");
214 // skyeye_exit (-1);
215 return 0; //No matter return value, only for compiler.
216}
217
218//------------------------------------------------------------------
219//xscale cp14 ----------------------------------------------------
220unsigned
221xscale_cp14_init (ARMul_State * state)
222{
223 //printf("SKYEYE: xscale_cp14_init: begin\n");
224 pxa_cp14_regs.cclkcfg = 0;
225 pxa_cp14_regs.pwrmode = 0;
226 return 0;
227}
228
229unsigned
230xscale_cp14_exit (ARMul_State * state)
231{
232 //printf("SKYEYE: xscale_cp14_exit: begin\n");
233 return 0;
234}
235
236unsigned
237xscale_cp14_ldc (ARMul_State * state, unsigned type, ARMword instr,
238 ARMword data)
239{
240 printf ("SKYEYE: xscale_cp14_ldc: ERROR isn't existed, reg15 0x%x\n",
241 state->Reg[15]);
242 SKYEYE_OUTREGS (stderr);
243 // skyeye_exit (-1);
244 return 0; //No matter return value, only for compiler.
245}
246
247unsigned
248xscale_cp14_stc (ARMul_State * state, unsigned type, ARMword instr,
249 ARMword * data)
250{
251 printf ("SKYEYE: xscale_cp14_stc: ERROR isn't existed, reg15 0x%x\n",
252 state->Reg[15]);
253 SKYEYE_OUTREGS (stderr);
254 // skyeye_exit (-1);
255 return 0; //No matter return value, only for compiler.
256}
257
258unsigned
259xscale_cp14_mrc (ARMul_State * state, unsigned type, ARMword instr,
260 ARMword * data)
261{
262 unsigned opcode_2 = BITS (5, 7);
263 unsigned CRm = BITS (0, 3);
264 unsigned reg = BITS (16, 19);
265 unsigned result;
266
267 //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,\
268 state->Reg[15], instr);
269
270 switch (reg) {
271 case CCLKCFG: // cp 14 reg 6
272 //printf("cp14_mrc cclkcfg \n");
273 *data = pxa_cp14_regs.cclkcfg;
274 break;
275 case PWRMODE: // cp 14 reg 7
276 //printf("cp14_mrc pwrmode \n");
277 *data = pxa_cp14_regs.pwrmode;
278 break;
279 default:
280 *data = 0;
281 printf ("SKYEYE:cp14_mrc unknown cp14 regs!!!!!!\n");
282 break;
283 }
284 return 0;
285}
286unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, ARMword instr,
287 ARMword data)
288{
289 unsigned opcode_2 = BITS (5, 7);
290 unsigned CRm = BITS (0, 3);
291 unsigned reg = BITS (16, 19);
292 unsigned result;
293
294 //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,\
295 state->Reg[15], instr);
296
297 switch (reg) {
298 case CCLKCFG: // cp 14 reg 6
299 //printf("cp14_mcr cclkcfg \n");
300 pxa_cp14_regs.cclkcfg = data & 0xf;
301 break;
302 case PWRMODE: // cp 14 reg 7
303 //printf("cp14_mcr pwrmode \n");
304 pxa_cp14_regs.pwrmode = data & 0x3;
305 break;
306 default:printf ("SKYEYE: cp14_mcr unknown cp14 regs!!!!!!\n");
307 break;
308 }
309 return 0;
310}
311unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, ARMword instr)
312{
313 printf ("SKYEYE: xscale_cp14_cdp: ERROR isn't existed, reg15 0x%x\n",
314 state->Reg[15]);
315 SKYEYE_OUTREGS (stderr);
316 // skyeye_exit (-1);
317 return 0; //No matter return value, only for compiler.
318}
319unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg,
320 ARMword * data)
321{
322 printf ("SKYEYE: xscale_cp14_read_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]);
323 SKYEYE_OUTREGS (stderr);
324 // skyeye_exit (-1);
325 return 0; //No matter return value, only for compiler.
326}
327unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg,
328 ARMword data)
329{
330 printf ("SKYEYE: xscale_cp14_write_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]);
331 SKYEYE_OUTREGS (stderr);
332 // skyeye_exit (-1);
333
334 return 0; //No matter return value, only for compiler.
335}
336
337//------------------------------------------------------------------
338//cp15 -------------------------------------
339unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, ARMword instr,
340 ARMword data)
341{
342 printf ("SKYEYE: xscale_cp15_ldc: ERROR isn't existed\n");
343 SKYEYE_OUTREGS (stderr);
344 // skyeye_exit (-1);
345
346 return 0; //No matter return value, only for compiler.
347}
348unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, ARMword instr,
349 ARMword * data)
350{
351 printf ("SKYEYE: xscale_cp15_stc: ERROR isn't existed\n");
352 SKYEYE_OUTREGS (stderr);
353 // skyeye_exit (-1);
354
355 return 0; //No matter return value, only for compiler.
356}
357unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, ARMword instr)
358{
359 printf ("SKYEYE: xscale_cp15_cdp: ERROR isn't existed\n");
360 SKYEYE_OUTREGS (stderr);
361 // skyeye_exit (-1);
362
363 return 0; //No matter return value, only for compiler.
364}
365unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg,
366 ARMword * data)
367{
368//chy 2003-09-03: for xsacle_cp15_cp_access_allowed
369 if (reg == 15) {
370 *data = state->mmu.copro_access;
371 //printf("SKYEYE: xscale_cp15_read_reg: reg 0x%x,data %x\n",reg,*data);
372 return 0;
373 }
374 printf ("SKYEYE: xscale_cp15_read_reg: reg 0x%x, ERROR isn't existed\n", reg);
375 SKYEYE_OUTREGS (stderr);
376 // skyeye_exit (-1);
377
378 return 0; //No matter return value, only for compiler.
379}
380
381//chy 2003-09-03 used by macro CP_ACCESS_ALLOWED in armemu.h
382unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
383 unsigned cpnum)
384{
385 unsigned data;
386
387 xscale_cp15_read_reg (state, reg, &data);
388 //printf("SKYEYE: cp15_cp_access_allowed data %x, cpnum %x, result %x\n", data, cpnum, (data & 1<<cpnum));
389 if (data & 1 << cpnum)
390 return 1;
391 else
392 return 0;
393}
394
395unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg,
396 ARMword value)
397{
398 switch (reg) {
399 case MMU_FAULT_STATUS:
400 //printf("SKYEYE:cp15_write_reg wrote FS val 0x%x \n",value);
401 state->mmu.fault_status = value & 0x6FF;
402 break;
403 case MMU_FAULT_ADDRESS:
404 //printf("SKYEYE:cp15_write_reg wrote FA val 0x%x \n",value);
405 state->mmu.fault_address = value;
406 break;
407 default:
408 printf ("SKYEYE: xscale_cp15_write_reg: reg 0x%x R15 %x ERROR isn't existed\n", reg, state->Reg[15]);
409 SKYEYE_OUTREGS (stderr);
410 // skyeye_exit (-1);
411 }
412 return 0;
413}
414
415unsigned
416xscale_cp15_init (ARMul_State * state)
417{
418 xscale_mmu_desc_t *desc;
419 cache_desc_t *c_desc;
420
421 state->mmu.control = 0;
422 state->mmu.translation_table_base = 0xDEADC0DE;
423 state->mmu.domain_access_control = 0xDEADC0DE;
424 state->mmu.fault_status = 0;
425 state->mmu.fault_address = 0;
426 state->mmu.process_id = 0;
427 state->mmu.cache_type = 0xB1AA1AA; //0000 1011 0001 1010 1010 0001 1010 1010
428 state->mmu.aux_control = 0;
429
430 desc = &pxa_mmu_desc;
431
432 if (mmu_tlb_init (I_TLB (), desc->i_tlb)) {
433 ERROR_LOG(ARM11, "i_tlb init %d\n", -1);
434 goto i_tlb_init_error;
435 }
436
437 c_desc = &desc->i_cache;
438 if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way,
439 c_desc->set, c_desc->w_mode)) {
440 ERROR_LOG(ARM11, "i_cache init %d\n", -1);
441 goto i_cache_init_error;
442 }
443
444 if (mmu_tlb_init (D_TLB (), desc->d_tlb)) {
445 ERROR_LOG(ARM11, "d_tlb init %d\n", -1);
446 goto d_tlb_init_error;
447 }
448
449 c_desc = &desc->main_d_cache;
450 if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way,
451 c_desc->set, c_desc->w_mode)) {
452 ERROR_LOG(ARM11, "main_d_cache init %d\n", -1);
453 goto main_d_cache_init_error;
454 }
455
456 c_desc = &desc->mini_d_cache;
457 if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way,
458 c_desc->set, c_desc->w_mode)) {
459 ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1);
460 goto mini_d_cache_init_error;
461 }
462
463 if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) {
464 ERROR_LOG(ARM11, "wb init %d\n", -1);
465 goto wb_init_error;
466 }
467#if 0
468 if (mmu_rb_init (RB (), desc->rb)) {
469 ERROR_LOG(ARM11, "rb init %d\n", -1);
470 goto rb_init_error;
471 }
472#endif
473
474 return 0;
475#if 0
476 rb_init_error:
477 mmu_wb_exit (WB ());
478#endif
479 wb_init_error:
480 mmu_cache_exit (MINI_D_CACHE ());
481 mini_d_cache_init_error:
482 mmu_cache_exit (MAIN_D_CACHE ());
483 main_d_cache_init_error:
484 mmu_tlb_exit (D_TLB ());
485 d_tlb_init_error:
486 mmu_cache_exit (I_CACHE ());
487 i_cache_init_error:
488 mmu_tlb_exit (I_TLB ());
489 i_tlb_init_error:
490 return -1;
491}
492
493unsigned
494xscale_cp15_exit (ARMul_State * state)
495{
496 //mmu_rb_exit(RB());
497 mmu_wb_exit (WB ());
498 mmu_cache_exit (MINI_D_CACHE ());
499 mmu_cache_exit (MAIN_D_CACHE ());
500 mmu_tlb_exit (D_TLB ());
501 mmu_cache_exit (I_CACHE ());
502 mmu_tlb_exit (I_TLB ());
503 return 0;
504};
505
506
507static fault_t
508 xscale_mmu_load_instr (ARMul_State * state, ARMword va,
509 ARMword * instr)
510{
511 fault_t fault;
512 tlb_entry_t *tlb;
513 cache_line_t *cache;
514 int c; //cache bit
515 ARMword pa; //physical addr
516
517 static int debug_count = 0; //used for debug
518
519 DEBUG_LOG(ARM11, "va = %x\n", va);
520
521 va = mmu_pid_va_map (va);
522 if (MMU_Enabled) {
523 /*align check */
524 if ((va & (INSN_SIZE - 1)) && MMU_Aligned) {
525 DEBUG_LOG(ARM11, "align\n");
526 return ALIGNMENT_FAULT;
527 }
528 else
529 va &= ~(INSN_SIZE - 1);
530
531 /*translate tlb */
532 fault = translate (state, va, I_TLB (), &tlb);
533 if (fault) {
534 DEBUG_LOG(ARM11, "translate\n");
535 return fault;
536 }
537
538 /*check access */
539 fault = check_access (state, va, tlb, 1);
540 if (fault) {
541 DEBUG_LOG(ARM11, "check_fault\n");
542 return fault;
543 }
544 }
545 //chy 2003-09-02 for test, don't use cache ?????
546#if 0
547 /*search cache no matter MMU enabled/disabled */
548 cache = mmu_cache_search (state, I_CACHE (), va);
549 if (cache) {
550 *instr = cache->data[va_cache_index (va, I_CACHE ())];
551 return 0;
552 }
553#endif
554 /*if MMU disabled or C flag is set alloc cache */
555 if (MMU_Disabled) {
556 c = 1;
557 pa = va;
558 }
559 else {
560 c = tlb_c_flag (tlb);
561 pa = tlb_va_to_pa (tlb, va);
562 }
563
564 //chy 2003-09-03 only read mem, don't use cache now,will change later ????
565 //*instr = mem_read_word (state, pa);
566 bus_read(32, pa, instr);
567#if 0
568//-----------------------------------------------------------
569 //chy 2003-09-02 for test????
570 if (pa >= 0xa01c8000 && pa <= 0xa01c8020) {
571 printf ("SKYEYE:load_instr: pa %x, va %x,instr %x, R15 %x\n",
572 pa, va, *instr, state->Reg[15]);
573 }
574
575//----------------------------------------------------------------------
576#endif
577 return NO_FAULT;
578
579 if (c) {
580 int index;
581
582 debug_count++;
583 cache = mmu_cache_alloc (state, I_CACHE (), va, pa);
584 index = va_cache_index (va, I_CACHE ());
585 *instr = cache->data[va_cache_index (va, I_CACHE ())];
586 }
587 else
588 //*instr = mem_read_word (state, pa);
589 bus_read(32, pa, instr);
590
591 return NO_FAULT;
592};
593
594
595
596static fault_t
597 xscale_mmu_read_byte (ARMul_State * state, ARMword virt_addr,
598 ARMword * data)
599{
600 //ARMword temp,offset;
601 fault_t fault;
602 fault = xscale_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE);
603 return fault;
604}
605
606static fault_t
607 xscale_mmu_read_halfword (ARMul_State * state, ARMword virt_addr,
608 ARMword * data)
609{
610 //ARMword temp,offset;
611 fault_t fault;
612 fault = xscale_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE);
613 return fault;
614}
615
616static fault_t
617 xscale_mmu_read_word (ARMul_State * state, ARMword virt_addr,
618 ARMword * data)
619{
620 return xscale_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);
621}
622
623
624
625
626static fault_t
627 xscale_mmu_read (ARMul_State * state, ARMword va, ARMword * data,
628 ARMword datatype)
629{
630 fault_t fault;
631// rb_entry_t *rb;
632 tlb_entry_t *tlb;
633 cache_line_t *cache;
634 ARMword pa, real_va, temp, offset;
635 //chy 2003-09-02 for test ????
636 static unsigned chyst1 = 0, chyst2 = 0;
637
638 DEBUG_LOG(ARM11, "va = %x\n", va);
639
640 va = mmu_pid_va_map (va);
641 real_va = va;
642 /*if MMU disabled, memory_read */
643 if (MMU_Disabled) {
644 //*data = mem_read_word(state, va);
645 if (datatype == ARM_BYTE_TYPE)
646 //*data = mem_read_byte (state, va);
647 bus_read(8, va, data);
648 else if (datatype == ARM_HALFWORD_TYPE)
649 //*data = mem_read_halfword (state, va);
650 bus_read(16, va, data);
651 else if (datatype == ARM_WORD_TYPE)
652 //*data = mem_read_word (state, va);
653 bus_read(32, va, data);
654 else {
655 printf ("SKYEYE:1 xscale_mmu_read error: unknown data type %d\n", datatype);
656 // skyeye_exit (-1);
657 }
658
659 return NO_FAULT;
660 }
661
662 /*align check */
663 if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
664 ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
665 DEBUG_LOG(ARM11, "align\n");
666 return ALIGNMENT_FAULT;
667 } // else
668
669 va &= ~(WORD_SIZE - 1);
670
671 /*translate va to tlb */
672 fault = translate (state, va, D_TLB (), &tlb);
673 if (fault) {
674 DEBUG_LOG(ARM11, "translate\n");
675 return fault;
676 }
677 /*check access permission */
678 fault = check_access (state, va, tlb, 1);
679 if (fault)
680 return fault;
681
682#if 0
683//------------------------------------------------
684//chy 2003-09-02 for test only ,should commit ????
685 if (datatype == ARM_WORD_TYPE) {
686 if (real_va >= 0xffff0000 && real_va <= 0xffff0020) {
687 pa = tlb_va_to_pa (tlb, va);
688 *data = mem_read_word (state, pa);
689 chyst1++;
690 printf ("**SKYEYE:mmu_read word %d: pa %x, va %x, data %x, R15 %x\n", chyst1, pa, real_va, *data, state->Reg[15]);
691 /*
692 cache==mmu_cache_search(state,MAIN_D_CACHE(),va);
693 if(cache){
694 *data = cache->data[va_cache_index(va, MAIN_D_CACHE())];
695 printf("cached data %x\n",*data);
696 }else printf("no cached data\n");
697 */
698 }
699 }
700//-------------------------------------------------
701#endif
702#if 0
703 /*search in read buffer */
704 rb = mmu_rb_search (RB (), va);
705 if (rb) {
706 if (rb->fault)
707 return rb->fault;
708 *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT];
709 goto datatrans;
710 //return 0;
711 };
712#endif
713
714 /*2004-07-19 chy: add support of xscale MMU CacheDisabled option */
715 if (MMU_CacheDisabled) {
716 //if(1){ can be used to test cache error
717 /*get phy_addr */
718 pa = tlb_va_to_pa (tlb, real_va);
719 if (datatype == ARM_BYTE_TYPE)
720 //*data = mem_read_byte (state, pa);
721 bus_read(8, pa, data);
722 else if (datatype == ARM_HALFWORD_TYPE)
723 //*data = mem_read_halfword (state, pa);
724 bus_read(16, pa, data);
725 else if (datatype == ARM_WORD_TYPE)
726 //*data = mem_read_word (state, pa);
727 bus_read(32, pa, data);
728 else {
729 printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_read error: unknown data type %d\n", datatype);
730 // skyeye_exit (-1);
731 }
732 return NO_FAULT;
733 }
734
735
736 /*search main cache */
737 cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
738 if (cache) {
739 *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())];
740#if 0
741//------------------------------------------------------------------------
742//chy 2003-09-02 for test only ,should commit ????
743 if (real_va >= 0xffff0000 && real_va <= 0xffff0020) {
744 pa = tlb_va_to_pa (tlb, va);
745 chyst2++;
746 printf ("**SKYEYE:mmu_read wordk:cache %d: pa %x, va %x, data %x, R15 %x\n", chyst2, pa, real_va, *data, state->Reg[15]);
747 }
748//-------------------------------------------------------------------
749#endif
750 goto datatrans;
751 //return 0;
752 }
753 //chy 2003-08-24, now maybe we don't need minidcache ????
754#if 0
755 /*search mini cache */
756 cache = mmu_cache_search (state, MINI_D_CACHE (), va);
757 if (cache) {
758 *data = cache->data[va_cache_index (va, MINI_D_CACHE ())];
759 goto datatrans;
760 //return 0;
761 }
762#endif
763 /*get phy_addr */
764 pa = tlb_va_to_pa (tlb, va);
765 //chy 2003-08-24 , in xscale it means what ?????
766#if 0
767 if ((pa >= 0xe0000000) && (pa < 0xe8000000)) {
768
769 if (tlb_c_flag (tlb)) {
770 if (tlb_b_flag (tlb)) {
771 mmu_cache_soft_flush (state, MAIN_D_CACHE (),
772 pa);
773 }
774 else {
775 mmu_cache_soft_flush (state, MINI_D_CACHE (),
776 pa);
777 }
778 }
779 return 0;
780 }
781#endif
782 //chy 2003-08-24, check phy addr
783 //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address
784 /*
785 if(pa >= 0xb0000000){
786 printf("SKYEYE:xscale_mmu_read: phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]);
787 return 0;
788 }
789 */
790
791 //chy 2003-08-24, now maybe we don't need wb ????
792#if 0
793 /*if Buffer, drain Write Buffer first */
794 if (tlb_b_flag (tlb))
795 mmu_wb_drain_all (state, WB ());
796#endif
797 /*alloc cache or mem_read */
798 if (tlb_c_flag (tlb) && MMU_DCacheEnabled) {
799 cache_s *cache_t;
800
801 if (tlb_b_flag (tlb))
802 cache_t = MAIN_D_CACHE ();
803 else
804 cache_t = MINI_D_CACHE ();
805 cache = mmu_cache_alloc (state, cache_t, va, pa);
806 *data = cache->data[va_cache_index (va, cache_t)];
807 }
808 else {
809 //*data = mem_read_word(state, pa);
810 if (datatype == ARM_BYTE_TYPE)
811 //*data = mem_read_byte (state, pa | (real_va & 3));
812 bus_read(8, pa | (real_va & 3), data);
813 else if (datatype == ARM_HALFWORD_TYPE)
814 //*data = mem_read_halfword (state, pa | (real_va & 2));
815 bus_read(16, pa | (real_va & 2), data);
816 else if (datatype == ARM_WORD_TYPE)
817 //*data = mem_read_word (state, pa);
818 bus_read(32, pa, data);
819 else {
820 printf ("SKYEYE:2 xscale_mmu_read error: unknown data type %d\n", datatype);
821 // skyeye_exit (-1);
822 }
823 return NO_FAULT;
824 }
825
826
827 datatrans:
828 if (datatype == ARM_HALFWORD_TYPE) {
829 temp = *data;
830 offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
831 *data = (temp >> offset) & 0xffff;
832 }
833 else if (datatype == ARM_BYTE_TYPE) {
834 temp = *data;
835 offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
836 *data = (temp >> offset & 0xffL);
837 }
838 end:
839 return NO_FAULT;
840}
841
842
843static fault_t
844 xscale_mmu_write_byte (ARMul_State * state, ARMword virt_addr,
845 ARMword data)
846{
847 return xscale_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);
848}
849
850static fault_t
851 xscale_mmu_write_halfword (ARMul_State * state, ARMword virt_addr,
852 ARMword data)
853{
854 return xscale_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);
855}
856
857static fault_t
858 xscale_mmu_write_word (ARMul_State * state, ARMword virt_addr,
859 ARMword data)
860{
861 return xscale_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);
862}
863
864
865
866static fault_t
867 xscale_mmu_write (ARMul_State * state, ARMword va, ARMword data,
868 ARMword datatype)
869{
870 tlb_entry_t *tlb;
871 cache_line_t *cache;
872 cache_s *cache_t;
873 int b;
874 ARMword pa, real_va, temp, offset;
875 fault_t fault;
876
877 ARMword index;
878//chy 2003-09-02 for test ????
879// static unsigned chyst1=0,chyst2=0;
880
881 DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data);
882 va = mmu_pid_va_map (va);
883 real_va = va;
884
885 if (MMU_Disabled) {
886 //mem_write_word(state, va, data);
887 if (datatype == ARM_BYTE_TYPE)
888 //mem_write_byte (state, va, data);
889 bus_write(8, va, data);
890 else if (datatype == ARM_HALFWORD_TYPE)
891 //mem_write_halfword (state, va, data);
892 bus_write(16, va, data);
893 else if (datatype == ARM_WORD_TYPE)
894 //mem_write_word (state, va, data);
895 bus_write(32, va, data);
896 else {
897 printf ("SKYEYE:1 xscale_mmu_write error: unknown data type %d\n", datatype);
898 // skyeye_exit (-1);
899 }
900
901 return NO_FAULT;
902 }
903 /*align check */
904 if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) ||
905 ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) {
906 DEBUG_LOG(ARM11, "align\n");
907 return ALIGNMENT_FAULT;
908 } //else
909 va &= ~(WORD_SIZE - 1);
910 /*tlb translate */
911 fault = translate (state, va, D_TLB (), &tlb);
912 if (fault) {
913 DEBUG_LOG(ARM11, "translate\n");
914 return fault;
915 }
916 /*tlb check access */
917 fault = check_access (state, va, tlb, 0);
918 if (fault) {
919 DEBUG_LOG(ARM11, "check_access\n");
920 return fault;
921 }
922
923 /*2004-07-19 chy: add support for xscale MMU_CacheDisabled */
924 if (MMU_CacheDisabled) {
925 //if(1){ can be used to test the cache error
926 /*get phy_addr */
927 pa = tlb_va_to_pa (tlb, real_va);
928 if (datatype == ARM_BYTE_TYPE)
929 //mem_write_byte (state, pa, data);
930 bus_write(8, pa, data);
931 else if (datatype == ARM_HALFWORD_TYPE)
932 //mem_write_halfword (state, pa, data);
933 bus_write(16, pa, data);
934 else if (datatype == ARM_WORD_TYPE)
935 //mem_write_word (state, pa, data);
936 bus_write(32, pa , data);
937 else {
938 printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_write error: unknown data type %d\n", datatype);
939 // skyeye_exit (-1);
940 }
941
942 return NO_FAULT;
943 }
944
945 /*search main cache */
946 b = tlb_b_flag (tlb);
947 pa = tlb_va_to_pa (tlb, va);
948 cache = mmu_cache_search (state, MAIN_D_CACHE (), va);
949 if (cache) {
950 cache_t = MAIN_D_CACHE ();
951 goto has_cache;
952 }
953 //chy 2003-08-24, now maybe we don't need minidcache ????
954#if 0
955 /*search mini cache */
956 cache = mmu_cache_search (state, MINI_D_CACHE (), va);
957 if (cache) {
958 cache_t = MINI_D_CACHE ();
959 goto has_cache;
960 }
961#endif
962 b = tlb_b_flag (tlb);
963 pa = tlb_va_to_pa (tlb, va);
964 //chy 2003-08-24, check phy addr 0xa0000000, size 0x04000000
965 //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address
966 /*
967 if(pa >= 0xb0000000){
968 printf("SKYEYE:xscale_mmu_write phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]);
969 return 0;
970 }
971 */
972
973 //chy 2003-08-24, now maybe we don't need WB ????
974#if 0
975 if (b) {
976 if (MMU_WBEnabled) {
977 if (datatype == ARM_WORD_TYPE)
978 mmu_wb_write_bytes (state, WB (), pa, &data,
979 4);
980 else if (datatype == ARM_HALFWORD_TYPE)
981 mmu_wb_write_bytes (state, WB (),
982 (pa | (real_va & 2)),
983 &data, 2);
984 else if (datatype == ARM_BYTE_TYPE)
985 mmu_wb_write_bytes (state, WB (),
986 (pa | (real_va & 3)),
987 &data, 1);
988
989 }
990 else {
991 if (datatype == ARM_WORD_TYPE)
992 mem_write_word (state, pa, data);
993 else if (datatype == ARM_HALFWORD_TYPE)
994 mem_write_halfword (state,
995 (pa | (real_va & 2)),
996 data);
997 else if (datatype == ARM_BYTE_TYPE)
998 mem_write_byte (state, (pa | (real_va & 3)),
999 data);
1000 }
1001 }
1002 else {
1003
1004 mmu_wb_drain_all (state, WB ());
1005
1006 if (datatype == ARM_WORD_TYPE)
1007 mem_write_word (state, pa, data);
1008 else if (datatype == ARM_HALFWORD_TYPE)
1009 mem_write_halfword (state, (pa | (real_va & 2)),
1010 data);
1011 else if (datatype == ARM_BYTE_TYPE)
1012 mem_write_byte (state, (pa | (real_va & 3)), data);
1013 }
1014#endif
1015 //chy 2003-08-24, just write phy addr
1016 if (datatype == ARM_WORD_TYPE)
1017 //mem_write_word (state, pa, data);
1018 bus_write(32, pa, data);
1019 else if (datatype == ARM_HALFWORD_TYPE)
1020 //mem_write_halfword (state, (pa | (real_va & 2)), data);
1021 bus_write(16, pa | (real_va & 2), data);
1022 else if (datatype == ARM_BYTE_TYPE)
1023 //mem_write_byte (state, (pa | (real_va & 3)), data);
1024 bus_write(8, (pa | (real_va & 3)), data);
1025#if 0
1026//-------------------------------------------------------------
1027//chy 2003-09-02 for test ????
1028 if (datatype == ARM_WORD_TYPE) {
1029 if (real_va >= 0xffff0000 && real_va <= 0xffff0020) {
1030 printf ("**SKYEYE:mmu_write word: pa %x, va %x, data %x, R15 %x \n", pa, real_va, data, state->Reg[15]);
1031 }
1032 }
1033//--------------------------------------------------------------
1034#endif
1035 return NO_FAULT;
1036
1037 has_cache:
1038 index = va_cache_index (va, cache_t);
1039 //cache->data[index] = data;
1040
1041 if (datatype == ARM_WORD_TYPE)
1042 cache->data[index] = data;
1043 else if (datatype == ARM_HALFWORD_TYPE) {
1044 temp = cache->data[index];
1045 offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */
1046 cache->data[index] =
1047 (temp & ~(0xffffL << offset)) | ((data & 0xffffL) <<
1048 offset);
1049 }
1050 else if (datatype == ARM_BYTE_TYPE) {
1051 temp = cache->data[index];
1052 offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */
1053 cache->data[index] =
1054 (temp & ~(0xffL << offset)) | ((data & 0xffL) <<
1055 offset);
1056 }
1057
1058 if (index < (cache_t->width >> (WORD_SHT + 1)))
1059 cache->tag |= TAG_FIRST_HALF_DIRTY;
1060 else
1061 cache->tag |= TAG_LAST_HALF_DIRTY;
1062//-------------------------------------------------------------
1063//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
1064#if 0
1065 {
1066 if (datatype == ARM_WORD_TYPE)
1067 mem_write_word (state, pa, data);
1068 else if (datatype == ARM_HALFWORD_TYPE)
1069 mem_write_halfword (state, (pa | (real_va & 2)),
1070 data);
1071 else if (datatype == ARM_BYTE_TYPE)
1072 mem_write_byte (state, (pa | (real_va & 3)), data);
1073 }
1074#endif
1075#if 0
1076//chy 2003-09-02 for test ????
1077 if (datatype == ARM_WORD_TYPE) {
1078 if (real_va >= 0xffff0000 && real_va <= 0xffff0020) {
1079 printf ("**SKYEYE:mmu_write word:cache: pa %x, va %x, data %x, R15 %x\n", pa, real_va, data, state->Reg[15]);
1080 }
1081 }
1082//-------------------------------------------------------------
1083#endif
1084 if (datatype == ARM_WORD_TYPE)
1085 //mem_write_word (state, pa, data);
1086 bus_write(32, pa, data);
1087 else if (datatype == ARM_HALFWORD_TYPE)
1088 //mem_write_halfword (state, (pa | (real_va & 2)), data);
1089 bus_write(16, pa | (real_va & 2), data);
1090 else if (datatype == ARM_BYTE_TYPE)
1091 //mem_write_byte (state, (pa | (real_va & 3)), data);
1092 bus_write(8, (pa | (real_va & 3)), data);
1093 return NO_FAULT;
1094}
1095
1096ARMword xscale_cp15_mrc (ARMul_State * state,
1097 unsigned type, ARMword instr, ARMword * value)
1098{
1099 return xscale_mmu_mrc (state, instr, value);
1100}
1101
1102ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value)
1103{
1104 ARMword data;
1105 unsigned opcode_2 = BITS (5, 7);
1106 unsigned CRm = BITS (0, 3);
1107 unsigned reg = BITS (16, 19);
1108 unsigned result;
1109 mmu_regnum_t creg = (mmu_regnum_t)reg;
1110
1111/*
1112 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,\
1113 state->Reg[15], instr);
1114*/
1115 switch (creg) {
1116 case MMU_ID: //XSCALE_CP15
1117 //printf("mmu_mrc read ID \n");
1118 data = (opcode_2 ? state->mmu.cache_type : state->cpu->
1119 cpu_val);
1120 break;
1121 case MMU_CONTROL: //XSCALE_CP15_AUX_CONTROL
1122 //printf("mmu_mrc read CONTROL \n");
1123 data = (opcode_2 ? state->mmu.aux_control : state->mmu.
1124 control);
1125 break;
1126 case MMU_TRANSLATION_TABLE_BASE:
1127 //printf("mmu_mrc read TTB \n");
1128 data = state->mmu.translation_table_base;
1129 break;
1130 case MMU_DOMAIN_ACCESS_CONTROL:
1131 //printf("mmu_mrc read DACR \n");
1132 data = state->mmu.domain_access_control;
1133 break;
1134 case MMU_FAULT_STATUS:
1135 //printf("mmu_mrc read FSR \n");
1136 data = state->mmu.fault_status;
1137 break;
1138 case MMU_FAULT_ADDRESS:
1139 //printf("mmu_mrc read FAR \n");
1140 data = state->mmu.fault_address;
1141 break;
1142 case MMU_PID:
1143 //printf("mmu_mrc read PID \n");
1144 data = state->mmu.process_id;
1145 case XSCALE_CP15_COPRO_ACCESS:
1146 //printf("xscale cp15 read coprocessor access\n");
1147 data = state->mmu.copro_access;
1148 break;
1149 default:
1150 data = 0;
1151 printf ("SKYEYE: xscale_cp15_mrc read UNKNOWN - reg %d, pc 0x%x\n", creg, state->Reg[15]);
1152 // skyeye_exit (-1);
1153 break;
1154 }
1155 *value = data;
1156 //printf("SKYEYE: xscale_cp15_mrc:end value 0x%x\n",data);
1157 return ARMul_DONE;
1158}
1159
1160void xscale_cp15_cache_ops (ARMul_State * state, ARMword instr, ARMword value)
1161{
1162//chy: 2003-08-24 now, the BTB isn't simualted ....????
1163
1164 unsigned CRm, OPC_2;
1165
1166 CRm = BITS (0, 3);
1167 OPC_2 = BITS (5, 7);
1168 //err_msg("SKYEYE: xscale cp15_cache_ops:OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm,state->Reg[15]);
1169
1170 if (OPC_2 == 0 && CRm == 7) {
1171 mmu_cache_invalidate_all (state, I_CACHE ());
1172 mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
1173 return;
1174 }
1175
1176 if (OPC_2 == 0 && CRm == 5) {
1177 mmu_cache_invalidate_all (state, I_CACHE ());
1178 return;
1179 }
1180 if (OPC_2 == 1 && CRm == 5) {
1181 mmu_cache_invalidate (state, I_CACHE (), value);
1182 return;
1183 }
1184
1185 if (OPC_2 == 0 && CRm == 6) {
1186 mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
1187 return;
1188 }
1189
1190 if (OPC_2 == 1 && CRm == 6) {
1191 mmu_cache_invalidate (state, MAIN_D_CACHE (), value);
1192 return;
1193 }
1194
1195 if (OPC_2 == 1 && CRm == 0xa) {
1196 mmu_cache_clean (state, MAIN_D_CACHE (), value);
1197 return;
1198 }
1199
1200 if (OPC_2 == 4 && CRm == 0xa) {
1201 mmu_wb_drain_all (state, WB ());
1202 return;
1203 }
1204
1205 if (OPC_2 == 6 && CRm == 5) {
1206 //chy 2004-07-19 shoud fix in the future????!!!!
1207 //printf("SKYEYE: xscale_cp15_cache_ops:invalidate BTB CANT!!!!!!!!!!\n");
1208 //exit(-1);
1209 return;
1210 }
1211
1212 if (OPC_2 == 5 && CRm == 2) {
1213 //printf("SKYEYE: cp15_c_o: A L in D C, value %x, reg15 %x\n",value, state->Reg[15]);
1214 //exit(-1);
1215 //chy 2003-09-01 for test
1216 mmu_cache_invalidate_all (state, MAIN_D_CACHE ());
1217 return;
1218 }
1219
1220 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]);
1221 // skyeye_exit (-1);
1222}
1223
1224static void
1225 xscale_cp15_tlb_ops (ARMul_State * state, ARMword instr,
1226 ARMword value)
1227{
1228 int CRm, OPC_2;
1229
1230 CRm = BITS (0, 3);
1231 OPC_2 = BITS (5, 7);
1232
1233
1234 //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]);
1235 if (OPC_2 == 0 && CRm == 0x7) {
1236 mmu_tlb_invalidate_all (state, I_TLB ());
1237 mmu_tlb_invalidate_all (state, D_TLB ());
1238 return;
1239 }
1240
1241 if (OPC_2 == 0 && CRm == 0x5) {
1242 mmu_tlb_invalidate_all (state, I_TLB ());
1243 return;
1244 }
1245
1246 if (OPC_2 == 1 && CRm == 0x5) {
1247 mmu_tlb_invalidate_entry (state, I_TLB (), value);
1248 return;
1249 }
1250
1251 if (OPC_2 == 0 && CRm == 0x6) {
1252 mmu_tlb_invalidate_all (state, D_TLB ());
1253 return;
1254 }
1255
1256 if (OPC_2 == 1 && CRm == 0x6) {
1257 mmu_tlb_invalidate_entry (state, D_TLB (), value);
1258 return;
1259 }
1260
1261 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]);
1262 // skyeye_exit (-1);
1263}
1264
1265
1266ARMword xscale_cp15_mcr (ARMul_State * state,
1267 unsigned type, ARMword instr, ARMword value)
1268{
1269 return xscale_mmu_mcr (state, instr, value);
1270}
1271
1272ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value)
1273{
1274 ARMword data;
1275 unsigned opcode_2 = BITS (5, 7);
1276 unsigned CRm = BITS (0, 3);
1277 unsigned reg = BITS (16, 19);
1278 unsigned result;
1279 mmu_regnum_t creg = (mmu_regnum_t)reg;
1280
1281 //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);
1282
1283 switch (creg) {
1284 case MMU_CONTROL:
1285 //printf("mmu_mcr wrote CONTROL val 0x%x \n",value);
1286 state->mmu.control =
1287 (opcode_2 ? (value & 0x33) : (value & 0x3FFF));
1288 break;
1289 case MMU_TRANSLATION_TABLE_BASE:
1290 //printf("mmu_mcr wrote TTB val 0x%x \n",value);
1291 state->mmu.translation_table_base = value & 0xFFFFC000;
1292 break;
1293 case MMU_DOMAIN_ACCESS_CONTROL:
1294 //printf("mmu_mcr wrote DACR val 0x%x \n",value);
1295 state->mmu.domain_access_control = value;
1296 break;
1297
1298 case MMU_FAULT_STATUS:
1299 //printf("mmu_mcr wrote FS val 0x%x \n",value);
1300 state->mmu.fault_status = value & 0x6FF;
1301 break;
1302 case MMU_FAULT_ADDRESS:
1303 //printf("mmu_mcr wrote FA val 0x%x \n",value);
1304 state->mmu.fault_address = value;
1305 break;
1306
1307 case MMU_CACHE_OPS:
1308// printf("mmu_mcr wrote CO val 0x%x \n",value);
1309 xscale_cp15_cache_ops (state, instr, value);
1310 break;
1311 case MMU_TLB_OPS:
1312 //printf("mmu_mcr wrote TO val 0x%x \n",value);
1313 xscale_cp15_tlb_ops (state, instr, value);
1314 break;
1315 case MMU_PID:
1316 //printf("mmu_mcr wrote PID val 0x%x \n",value);
1317 state->mmu.process_id = value & 0xfe000000;
1318 break;
1319 case XSCALE_CP15_COPRO_ACCESS:
1320 //printf("xscale cp15 write coprocessor access val 0x %x\n",value);
1321 state->mmu.copro_access = value & 0x3ff;
1322 break;
1323
1324 default:
1325 printf ("SKYEYE: xscale_cp15_mcr wrote UNKNOWN - reg %d, reg15 0x%x\n", creg, state->Reg[15]);
1326 break;
1327 }
1328 //printf("SKYEYE: xscale_cp15_mcr wrote val 0x%x\n", value);
1329 return 0;
1330}
1331
1332//teawater add for arm2x86 2005.06.24-------------------------------------------
1333static int xscale_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr,
1334 ARMword * phys_addr)
1335{
1336 fault_t fault;
1337 tlb_entry_t *tlb;
1338
1339 virt_addr = mmu_pid_va_map (virt_addr);
1340 if (MMU_Enabled) {
1341
1342 /*align check */
1343 if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) {
1344 DEBUG_LOG(ARM11, "align\n");
1345 return ALIGNMENT_FAULT;
1346 }
1347 else
1348 virt_addr &= ~(WORD_SIZE - 1);
1349
1350 /*translate tlb */
1351 fault = translate (state, virt_addr, I_TLB (), &tlb);
1352 if (fault) {
1353 DEBUG_LOG(ARM11, "translate\n");
1354 return fault;
1355 }
1356
1357 /*check access */
1358 fault = check_access (state, virt_addr, tlb, 1);
1359 if (fault) {
1360 DEBUG_LOG(ARM11, "check_fault\n");
1361 return fault;
1362 }
1363 }
1364
1365 if (MMU_Disabled) {
1366 *phys_addr = virt_addr;
1367 }
1368 else {
1369 *phys_addr = tlb_va_to_pa (tlb, virt_addr);
1370 }
1371
1372 return (0);
1373}
1374
1375//AJ2D--------------------------------------------------------------------------
1376
1377/*xscale mmu_ops_t*/
1378//mmu_ops_t xscale_mmu_ops = {
1379// xscale_cp15_init,
1380// xscale_cp15_exit,
1381// xscale_mmu_read_byte,
1382// xscale_mmu_write_byte,
1383// xscale_mmu_read_halfword,
1384// xscale_mmu_write_halfword,
1385// xscale_mmu_read_word,
1386// xscale_mmu_write_word,
1387// xscale_mmu_load_instr, xscale_mmu_mcr, xscale_mmu_mrc,
1388////teawater add for arm2x86 2005.06.24-------------------------------------------
1389// xscale_mmu_v2p_dbct,
1390////AJ2D--------------------------------------------------------------------------
1391//};
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 @@
19instruction into its corresponding ARM instruction, and using the 19instruction into its corresponding ARM instruction, and using the
20existing ARM simulator. */ 20existing ARM simulator. */
21 21
22#include "skyeye_defs.h" 22#include "core/arm/skyeye_common/skyeye_defs.h"
23 23
24#ifndef MODET /* required for the Thumb instruction support */ 24#ifndef MODET /* required for the Thumb instruction support */
25#if 1 25#if 1
@@ -29,9 +29,9 @@ existing ARM simulator. */
29#endif 29#endif
30#endif 30#endif
31 31
32#include "armdefs.h" 32#include "core/arm/skyeye_common/armdefs.h"
33#include "armemu.h" 33#include "core/arm/skyeye_common/armemu.h"
34#include "armos.h" 34#include "core/arm/skyeye_common/armos.h"
35 35
36 36
37/* Decode a 16bit Thumb instruction. The instruction is in the low 37/* 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 @@
1/*
2 armvfp.c - ARM VFPv3 emulation unit
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/* Note: this file handles interface with arm core and vfp registers */
22
23/* Opens debug for classic interpreter only */
24//#define DEBUG
25
26#include "common/common.h"
27
28#include "core/arm/interpreter/armdefs.h"
29#include "core/arm/interpreter/vfp/vfp.h"
30
31//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
32
33unsigned
34VFPInit (ARMul_State *state)
35{
36 state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
37 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
38 state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
39 state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
40
41 //persistent_state = state;
42 /* Reset only specify VFP_FPEXC_EN = '0' */
43
44 return No_exp;
45}
46
47unsigned
48VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
49{
50 /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
51 int CoProc = BITS (8, 11); /* 10 or 11 */
52 int OPC_1 = BITS (21, 23);
53 int Rt = BITS (12, 15);
54 int CRn = BITS (16, 19);
55 int CRm = BITS (0, 3);
56 int OPC_2 = BITS (5, 7);
57
58 /* TODO check access permission */
59
60 /* CRn/opc1 CRm/opc2 */
61
62 if (CoProc == 10 || CoProc == 11)
63 {
64 #define VFP_MRC_TRANS
65 #include "core/arm/interpreter/vfp/vfpinstr.cpp"
66 #undef VFP_MRC_TRANS
67 }
68 DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
69 instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
70
71 return ARMul_CANT;
72}
73
74unsigned
75VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
76{
77 /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
78 int CoProc = BITS (8, 11); /* 10 or 11 */
79 int OPC_1 = BITS (21, 23);
80 int Rt = BITS (12, 15);
81 int CRn = BITS (16, 19);
82 int CRm = BITS (0, 3);
83 int OPC_2 = BITS (5, 7);
84
85 /* TODO check access permission */
86
87 /* CRn/opc1 CRm/opc2 */
88 if (CoProc == 10 || CoProc == 11)
89 {
90 #define VFP_MCR_TRANS
91 #include "core/arm/interpreter/vfp/vfpinstr.cpp"
92 #undef VFP_MCR_TRANS
93 }
94 DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
95 instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
96
97 return ARMul_CANT;
98}
99
100unsigned
101VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2)
102{
103 /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
104 int CoProc = BITS (8, 11); /* 10 or 11 */
105 int OPC_1 = BITS (4, 7);
106 int Rt = BITS (12, 15);
107 int Rt2 = BITS (16, 19);
108 int CRm = BITS (0, 3);
109
110 if (CoProc == 10 || CoProc == 11)
111 {
112 #define VFP_MRRC_TRANS
113 #include "core/arm/interpreter/vfp/vfpinstr.cpp"
114 #undef VFP_MRRC_TRANS
115 }
116 DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
117 instr, CoProc, OPC_1, Rt, Rt2, CRm);
118
119 return ARMul_CANT;
120}
121
122unsigned
123VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2)
124{
125 /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
126 int CoProc = BITS (8, 11); /* 10 or 11 */
127 int OPC_1 = BITS (4, 7);
128 int Rt = BITS (12, 15);
129 int Rt2 = BITS (16, 19);
130 int CRm = BITS (0, 3);
131
132 /* TODO check access permission */
133
134 /* CRn/opc1 CRm/opc2 */
135
136 if (CoProc == 11 || CoProc == 10)
137 {
138 #define VFP_MCRR_TRANS
139 #include "core/arm/interpreter/vfp/vfpinstr.cpp"
140 #undef VFP_MCRR_TRANS
141 }
142 DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
143 instr, CoProc, OPC_1, Rt, Rt2, CRm);
144
145 return ARMul_CANT;
146}
147
148unsigned
149VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
150{
151 /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
152 int CoProc = BITS (8, 11); /* 10 or 11 */
153 int CRd = BITS (12, 15);
154 int Rn = BITS (16, 19);
155 int imm8 = BITS (0, 7);
156 int P = BIT(24);
157 int U = BIT(23);
158 int D = BIT(22);
159 int W = BIT(21);
160
161 /* TODO check access permission */
162
163 /* VSTM */
164 if ( (P|U|D|W) == 0 )
165 {
166 DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
167 }
168 if (CoProc == 10 || CoProc == 11)
169 {
170 #if 1
171 if (P == 0 && U == 0 && W == 0)
172 {
173 DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1);
174 }
175 if (P == U && W == 1)
176 {
177 DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1);
178 }
179 #endif
180
181 #define VFP_STC_TRANS
182 #include "core/arm/interpreter/vfp/vfpinstr.cpp"
183 #undef VFP_STC_TRANS
184 }
185 DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
186 instr, CoProc, CRd, Rn, imm8, P, U, D, W);
187
188 return ARMul_CANT;
189}
190
191unsigned
192VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
193{
194 /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
195 int CoProc = BITS (8, 11); /* 10 or 11 */
196 int CRd = BITS (12, 15);
197 int Rn = BITS (16, 19);
198 int imm8 = BITS (0, 7);
199 int P = BIT(24);
200 int U = BIT(23);
201 int D = BIT(22);
202 int W = BIT(21);
203
204 /* TODO check access permission */
205
206 if ( (P|U|D|W) == 0 )
207 {
208 DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
209 }
210 if (CoProc == 10 || CoProc == 11)
211 {
212 #define VFP_LDC_TRANS
213 #include "core/arm/interpreter/vfp/vfpinstr.cpp"
214 #undef VFP_LDC_TRANS
215 }
216 DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
217 instr, CoProc, CRd, Rn, imm8, P, U, D, W);
218
219 return ARMul_CANT;
220}
221
222unsigned
223VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
224{
225 /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
226 int CoProc = BITS (8, 11); /* 10 or 11 */
227 int OPC_1 = BITS (20, 23);
228 int CRd = BITS (12, 15);
229 int CRn = BITS (16, 19);
230 int CRm = BITS (0, 3);
231 int OPC_2 = BITS (5, 7);
232
233 /* TODO check access permission */
234
235 /* CRn/opc1 CRm/opc2 */
236
237 if (CoProc == 10 || CoProc == 11)
238 {
239 #define VFP_CDP_TRANS
240 #include "core/arm/interpreter/vfp/vfpinstr.cpp"
241 #undef VFP_CDP_TRANS
242
243 int exceptions = 0;
244 if (CoProc == 10)
245 exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
246 else
247 exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
248
249 vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
250
251 return ARMul_DONE;
252 }
253 DEBUG_LOG(ARM11, "Can't identify %x\n", instr);
254 return ARMul_CANT;
255}
256
257
258/* ----------- MRC ------------ */
259#define VFP_MRC_IMPL
260#include "core/arm/interpreter/vfp/vfpinstr.cpp"
261#undef VFP_MRC_IMPL
262
263#define VFP_MRRC_IMPL
264#include "core/arm/interpreter/vfp/vfpinstr.cpp"
265#undef VFP_MRRC_IMPL
266
267
268/* ----------- MCR ------------ */
269#define VFP_MCR_IMPL
270#include "core/arm/interpreter/vfp/vfpinstr.cpp"
271#undef VFP_MCR_IMPL
272
273#define VFP_MCRR_IMPL
274#include "core/arm/interpreter/vfp/vfpinstr.cpp"
275#undef VFP_MCRR_IMPL
276
277/* Memory operation are not inlined, as old Interpreter and Fast interpreter
278 don't have the same memory operation interface.
279 Old interpreter framework does one access to coprocessor per data, and
280 handles already data write, as well as address computation,
281 which is not the case for Fast interpreter. Therefore, implementation
282 of vfp instructions in old interpreter and fast interpreter are separate. */
283
284/* ----------- STC ------------ */
285#define VFP_STC_IMPL
286#include "core/arm/interpreter/vfp/vfpinstr.cpp"
287#undef VFP_STC_IMPL
288
289
290/* ----------- LDC ------------ */
291#define VFP_LDC_IMPL
292#include "core/arm/interpreter/vfp/vfpinstr.cpp"
293#undef VFP_LDC_IMPL
294
295
296/* ----------- CDP ------------ */
297#define VFP_CDP_IMPL
298#include "core/arm/interpreter/vfp/vfpinstr.cpp"
299#undef VFP_CDP_IMPL
300
301/* Miscellaneous functions */
302int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
303{
304 DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
305 return state->ExtReg[reg];
306}
307
308void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg)
309{
310 DBG("VFP put float: s%d <= [%08x]\n", reg, val);
311 state->ExtReg[reg] = val;
312}
313
314uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
315{
316 uint64_t result;
317 result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
318 DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
319 return result;
320}
321
322void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
323{
324 DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
325 state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
326 state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
327}
328
329
330
331/*
332 * Process bitmask of exception conditions. (from vfpmodule.c)
333 */
334void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
335{
336 int si_code = 0;
337
338 vfpdebug("VFP: raising exceptions %08x\n", exceptions);
339
340 if (exceptions == VFP_EXCEPTION_ERROR) {
341 DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst);
342 exit(-1);
343 return;
344 }
345
346 /*
347 * If any of the status flags are set, update the FPSCR.
348 * Comparison instructions always return at least one of
349 * these flags set.
350 */
351 if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
352 fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
353
354 fpscr |= exceptions;
355
356 state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
357}
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 @@
1/*
2 vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * This code is derived in part from :
23 * - Android kernel
24 * - John R. Housers softfloat library, which
25 * carries the following notice:
26 *
27 * ===========================================================================
28 * This C source file is part of the SoftFloat IEC/IEEE Floating-point
29 * Arithmetic Package, Release 2.
30 *
31 * Written by John R. Hauser. This work was made possible in part by the
32 * International Computer Science Institute, located at Suite 600, 1947 Center
33 * Street, Berkeley, California 94704. Funding was partially provided by the
34 * National Science Foundation under grant MIP-9311980. The original version
35 * of this code was written as part of a project to build a fixed-point vector
36 * processor in collaboration with the University of California at Berkeley,
37 * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
38 * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
39 * arithmetic/softfloat.html'.
40 *
41 * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
42 * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
43 * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
44 * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
45 * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
46 *
47 * Derivative works are acceptable, even for commercial purposes, so long as
48 * (1) they include prominent notice that the work is derivative, and (2) they
49 * include prominent notice akin to these three paragraphs for those parts of
50 * this code that are retained.
51 * ===========================================================================
52 */
53
54#include "core/arm/interpreter/vfp/vfp.h"
55#include "core/arm/interpreter/vfp/vfp_helper.h"
56#include "core/arm/interpreter/vfp/asm_vfp.h"
57
58static struct vfp_double vfp_double_default_qnan = {
59 //.exponent = 2047,
60 //.sign = 0,
61 //.significand = VFP_DOUBLE_SIGNIFICAND_QNAN,
62};
63
64static void vfp_double_dump(const char *str, struct vfp_double *d)
65{
66 pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
67 str, d->sign != 0, d->exponent, d->significand);
68}
69
70static void vfp_double_normalise_denormal(struct vfp_double *vd)
71{
72 int bits = 31 - vfp_fls(vd->significand >> 32);
73 if (bits == 31)
74 bits = 63 - vfp_fls(vd->significand);
75
76 vfp_double_dump("normalise_denormal: in", vd);
77
78 if (bits) {
79 vd->exponent -= bits - 1;
80 vd->significand <<= bits;
81 }
82
83 vfp_double_dump("normalise_denormal: out", vd);
84}
85
86u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
87{
88 u64 significand, incr;
89 int exponent, shift, underflow;
90 u32 rmode;
91
92 vfp_double_dump("pack: in", vd);
93
94 /*
95 * Infinities and NaNs are a special case.
96 */
97 if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
98 goto pack;
99
100 /*
101 * Special-case zero.
102 */
103 if (vd->significand == 0) {
104 vd->exponent = 0;
105 goto pack;
106 }
107
108 exponent = vd->exponent;
109 significand = vd->significand;
110
111 shift = 32 - vfp_fls(significand >> 32);
112 if (shift == 32)
113 shift = 64 - vfp_fls(significand);
114 if (shift) {
115 exponent -= shift;
116 significand <<= shift;
117 }
118
119#if 1
120 vd->exponent = exponent;
121 vd->significand = significand;
122 vfp_double_dump("pack: normalised", vd);
123#endif
124
125 /*
126 * Tiny number?
127 */
128 underflow = exponent < 0;
129 if (underflow) {
130 significand = vfp_shiftright64jamming(significand, -exponent);
131 exponent = 0;
132#if 1
133 vd->exponent = exponent;
134 vd->significand = significand;
135 vfp_double_dump("pack: tiny number", vd);
136#endif
137 if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
138 underflow = 0;
139 }
140
141 /*
142 * Select rounding increment.
143 */
144 incr = 0;
145 rmode = fpscr & FPSCR_RMODE_MASK;
146
147 if (rmode == FPSCR_ROUND_NEAREST) {
148 incr = 1ULL << VFP_DOUBLE_LOW_BITS;
149 if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
150 incr -= 1;
151 } else if (rmode == FPSCR_ROUND_TOZERO) {
152 incr = 0;
153 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
154 incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
155
156 pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
157
158 /*
159 * Is our rounding going to overflow?
160 */
161 if ((significand + incr) < significand) {
162 exponent += 1;
163 significand = (significand >> 1) | (significand & 1);
164 incr >>= 1;
165#if 1
166 vd->exponent = exponent;
167 vd->significand = significand;
168 vfp_double_dump("pack: overflow", vd);
169#endif
170 }
171
172 /*
173 * If any of the low bits (which will be shifted out of the
174 * number) are non-zero, the result is inexact.
175 */
176 if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
177 exceptions |= FPSCR_IXC;
178
179 /*
180 * Do our rounding.
181 */
182 significand += incr;
183
184 /*
185 * Infinity?
186 */
187 if (exponent >= 2046) {
188 exceptions |= FPSCR_OFC | FPSCR_IXC;
189 if (incr == 0) {
190 vd->exponent = 2045;
191 vd->significand = 0x7fffffffffffffffULL;
192 } else {
193 vd->exponent = 2047; /* infinity */
194 vd->significand = 0;
195 }
196 } else {
197 if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
198 exponent = 0;
199 if (exponent || significand > 0x8000000000000000ULL)
200 underflow = 0;
201 if (underflow)
202 exceptions |= FPSCR_UFC;
203 vd->exponent = exponent;
204 vd->significand = significand >> 1;
205 }
206
207 pack:
208 vfp_double_dump("pack: final", vd);
209 {
210 s64 d = vfp_double_pack(vd);
211 pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func,
212 dd, d, exceptions);
213 vfp_put_double(state, d, dd);
214 }
215 return exceptions;
216}
217
218/*
219 * Propagate the NaN, setting exceptions if it is signalling.
220 * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
221 */
222static u32
223vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
224 struct vfp_double *vdm, u32 fpscr)
225{
226 struct vfp_double *nan;
227 int tn, tm = 0;
228
229 tn = vfp_double_type(vdn);
230
231 if (vdm)
232 tm = vfp_double_type(vdm);
233
234 if (fpscr & FPSCR_DEFAULT_NAN)
235 /*
236 * Default NaN mode - always returns a quiet NaN
237 */
238 nan = &vfp_double_default_qnan;
239 else {
240 /*
241 * Contemporary mode - select the first signalling
242 * NAN, or if neither are signalling, the first
243 * quiet NAN.
244 */
245 if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
246 nan = vdn;
247 else
248 nan = vdm;
249 /*
250 * Make the NaN quiet.
251 */
252 nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
253 }
254
255 *vdd = *nan;
256
257 /*
258 * If one was a signalling NAN, raise invalid operation.
259 */
260 return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
261}
262
263/*
264 * Extended operations
265 */
266static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
267{
268 pr_debug("In %s\n", __FUNCTION__);
269 vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd);
270 return 0;
271}
272
273static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
274{
275 pr_debug("In %s\n", __FUNCTION__);
276 vfp_put_double(state, vfp_get_double(state, dm), dd);
277 return 0;
278}
279
280static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
281{
282 pr_debug("In %s\n", __FUNCTION__);
283 vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd);
284 return 0;
285}
286
287static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
288{
289 pr_debug("In %s\n", __FUNCTION__);
290 struct vfp_double vdm, vdd, *vdp;
291 int ret, tm;
292
293 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
294 tm = vfp_double_type(&vdm);
295 if (tm & (VFP_NAN|VFP_INFINITY)) {
296 vdp = &vdd;
297
298 if (tm & VFP_NAN)
299 ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
300 else if (vdm.sign == 0) {
301 sqrt_copy:
302 vdp = &vdm;
303 ret = 0;
304 } else {
305 sqrt_invalid:
306 vdp = &vfp_double_default_qnan;
307 ret = FPSCR_IOC;
308 }
309 vfp_put_double(state, vfp_double_pack(vdp), dd);
310 return ret;
311 }
312
313 /*
314 * sqrt(+/- 0) == +/- 0
315 */
316 if (tm & VFP_ZERO)
317 goto sqrt_copy;
318
319 /*
320 * Normalise a denormalised number
321 */
322 if (tm & VFP_DENORMAL)
323 vfp_double_normalise_denormal(&vdm);
324
325 /*
326 * sqrt(<0) = invalid
327 */
328 if (vdm.sign)
329 goto sqrt_invalid;
330
331 vfp_double_dump("sqrt", &vdm);
332
333 /*
334 * Estimate the square root.
335 */
336 vdd.sign = 0;
337 vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
338 vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
339
340 vfp_double_dump("sqrt estimate1", &vdd);
341
342 vdm.significand >>= 1 + (vdm.exponent & 1);
343 vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
344
345 vfp_double_dump("sqrt estimate2", &vdd);
346
347 /*
348 * And now adjust.
349 */
350 if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
351 if (vdd.significand < 2) {
352 vdd.significand = ~0ULL;
353 } else {
354 u64 termh, terml, remh, reml;
355 vdm.significand <<= 2;
356 mul64to128(&termh, &terml, vdd.significand, vdd.significand);
357 sub128(&remh, &reml, vdm.significand, 0, termh, terml);
358 while ((s64)remh < 0) {
359 vdd.significand -= 1;
360 shift64left(&termh, &terml, vdd.significand);
361 terml |= 1;
362 add128(&remh, &reml, remh, reml, termh, terml);
363 }
364 vdd.significand |= (remh | reml) != 0;
365 }
366 }
367 vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
368
369 return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt");
370}
371
372/*
373 * Equal := ZC
374 * Less than := N
375 * Greater than := C
376 * Unordered := CV
377 */
378static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr)
379{
380 s64 d, m;
381 u32 ret = 0;
382
383 pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr);
384 m = vfp_get_double(state, dm);
385 if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
386 ret |= FPSCR_C | FPSCR_V;
387 if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
388 /*
389 * Signalling NaN, or signalling on quiet NaN
390 */
391 ret |= FPSCR_IOC;
392 }
393
394 d = vfp_get_double(state, dd);
395 if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
396 ret |= FPSCR_C | FPSCR_V;
397 if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
398 /*
399 * Signalling NaN, or signalling on quiet NaN
400 */
401 ret |= FPSCR_IOC;
402 }
403
404 if (ret == 0) {
405 //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
406 if (d == m || vfp_double_packed_abs(d | m) == 0) {
407 /*
408 * equal
409 */
410 ret |= FPSCR_Z | FPSCR_C;
411 //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
412 } else if (vfp_double_packed_sign(d ^ m)) {
413 /*
414 * different signs
415 */
416 if (vfp_double_packed_sign(d))
417 /*
418 * d is negative, so d < m
419 */
420 ret |= FPSCR_N;
421 else
422 /*
423 * d is positive, so d > m
424 */
425 ret |= FPSCR_C;
426 } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
427 /*
428 * d < m
429 */
430 ret |= FPSCR_N;
431 } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
432 /*
433 * d > m
434 */
435 ret |= FPSCR_C;
436 }
437 }
438 pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret);
439
440 return ret;
441}
442
443static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
444{
445 pr_debug("In %s\n", __FUNCTION__);
446 return vfp_compare(state, dd, 0, dm, fpscr);
447}
448
449static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
450{
451 pr_debug("In %s\n", __FUNCTION__);
452 return vfp_compare(state, dd, 1, dm, fpscr);
453}
454
455static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
456{
457 pr_debug("In %s\n", __FUNCTION__);
458 return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr);
459}
460
461static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
462{
463 pr_debug("In %s\n", __FUNCTION__);
464 return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
465}
466
467static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
468{
469 struct vfp_double vdm;
470 struct vfp_single vsd;
471 int tm;
472 u32 exceptions = 0;
473
474 pr_debug("In %s\n", __FUNCTION__);
475 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
476
477 tm = vfp_double_type(&vdm);
478
479 /*
480 * If we have a signalling NaN, signal invalid operation.
481 */
482 if (tm == VFP_SNAN)
483 exceptions = FPSCR_IOC;
484
485 if (tm & VFP_DENORMAL)
486 vfp_double_normalise_denormal(&vdm);
487
488 vsd.sign = vdm.sign;
489 vsd.significand = vfp_hi64to32jamming(vdm.significand);
490
491 /*
492 * If we have an infinity or a NaN, the exponent must be 255
493 */
494 if (tm & (VFP_INFINITY|VFP_NAN)) {
495 vsd.exponent = 255;
496 if (tm == VFP_QNAN)
497 vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
498 goto pack_nan;
499 } else if (tm & VFP_ZERO)
500 vsd.exponent = 0;
501 else
502 vsd.exponent = vdm.exponent - (1023 - 127);
503
504 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
505
506 pack_nan:
507 vfp_put_float(state, vfp_single_pack(&vsd), sd);
508 return exceptions;
509}
510
511static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
512{
513 struct vfp_double vdm;
514 u32 m = vfp_get_float(state, dm);
515
516 pr_debug("In %s\n", __FUNCTION__);
517 vdm.sign = 0;
518 vdm.exponent = 1023 + 63 - 1;
519 vdm.significand = (u64)m;
520
521 return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito");
522}
523
524static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
525{
526 struct vfp_double vdm;
527 u32 m = vfp_get_float(state, dm);
528
529 pr_debug("In %s\n", __FUNCTION__);
530 vdm.sign = (m & 0x80000000) >> 16;
531 vdm.exponent = 1023 + 63 - 1;
532 vdm.significand = vdm.sign ? -m : m;
533
534 return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito");
535}
536
537static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
538{
539 struct vfp_double vdm;
540 u32 d, exceptions = 0;
541 int rmode = fpscr & FPSCR_RMODE_MASK;
542 int tm;
543
544 pr_debug("In %s\n", __FUNCTION__);
545 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
546
547 /*
548 * Do we have a denormalised number?
549 */
550 tm = vfp_double_type(&vdm);
551 if (tm & VFP_DENORMAL)
552 exceptions |= FPSCR_IDC;
553
554 if (tm & VFP_NAN)
555 vdm.sign = 0;
556
557 if (vdm.exponent >= 1023 + 32) {
558 d = vdm.sign ? 0 : 0xffffffff;
559 exceptions = FPSCR_IOC;
560 } else if (vdm.exponent >= 1023 - 1) {
561 int shift = 1023 + 63 - vdm.exponent;
562 u64 rem, incr = 0;
563
564 /*
565 * 2^0 <= m < 2^32-2^8
566 */
567 d = (vdm.significand << 1) >> shift;
568 rem = vdm.significand << (65 - shift);
569
570 if (rmode == FPSCR_ROUND_NEAREST) {
571 incr = 0x8000000000000000ULL;
572 if ((d & 1) == 0)
573 incr -= 1;
574 } else if (rmode == FPSCR_ROUND_TOZERO) {
575 incr = 0;
576 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
577 incr = ~0ULL;
578 }
579
580 if ((rem + incr) < rem) {
581 if (d < 0xffffffff)
582 d += 1;
583 else
584 exceptions |= FPSCR_IOC;
585 }
586
587 if (d && vdm.sign) {
588 d = 0;
589 exceptions |= FPSCR_IOC;
590 } else if (rem)
591 exceptions |= FPSCR_IXC;
592 } else {
593 d = 0;
594 if (vdm.exponent | vdm.significand) {
595 exceptions |= FPSCR_IXC;
596 if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
597 d = 1;
598 else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
599 d = 0;
600 exceptions |= FPSCR_IOC;
601 }
602 }
603 }
604
605 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
606
607 vfp_put_float(state, d, sd);
608
609 return exceptions;
610}
611
612static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
613{
614 pr_debug("In %s\n", __FUNCTION__);
615 return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO);
616}
617
618static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
619{
620 struct vfp_double vdm;
621 u32 d, exceptions = 0;
622 int rmode = fpscr & FPSCR_RMODE_MASK;
623 int tm;
624
625 pr_debug("In %s\n", __FUNCTION__);
626 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
627 vfp_double_dump("VDM", &vdm);
628
629 /*
630 * Do we have denormalised number?
631 */
632 tm = vfp_double_type(&vdm);
633 if (tm & VFP_DENORMAL)
634 exceptions |= FPSCR_IDC;
635
636 if (tm & VFP_NAN) {
637 d = 0;
638 exceptions |= FPSCR_IOC;
639 } else if (vdm.exponent >= 1023 + 32) {
640 d = 0x7fffffff;
641 if (vdm.sign)
642 d = ~d;
643 exceptions |= FPSCR_IOC;
644 } else if (vdm.exponent >= 1023 - 1) {
645 int shift = 1023 + 63 - vdm.exponent; /* 58 */
646 u64 rem, incr = 0;
647
648 d = (vdm.significand << 1) >> shift;
649 rem = vdm.significand << (65 - shift);
650
651 if (rmode == FPSCR_ROUND_NEAREST) {
652 incr = 0x8000000000000000ULL;
653 if ((d & 1) == 0)
654 incr -= 1;
655 } else if (rmode == FPSCR_ROUND_TOZERO) {
656 incr = 0;
657 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
658 incr = ~0ULL;
659 }
660
661 if ((rem + incr) < rem && d < 0xffffffff)
662 d += 1;
663 if (d > 0x7fffffff + (vdm.sign != 0)) {
664 d = 0x7fffffff + (vdm.sign != 0);
665 exceptions |= FPSCR_IOC;
666 } else if (rem)
667 exceptions |= FPSCR_IXC;
668
669 if (vdm.sign)
670 d = -d;
671 } else {
672 d = 0;
673 if (vdm.exponent | vdm.significand) {
674 exceptions |= FPSCR_IXC;
675 if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
676 d = 1;
677 else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
678 d = -1;
679 }
680 }
681
682 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
683
684 vfp_put_float(state, (s32)d, sd);
685
686 return exceptions;
687}
688
689static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
690{
691 pr_debug("In %s\n", __FUNCTION__);
692 return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO);
693}
694
695static struct op fops_ext[] = {
696 { vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY
697 { vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS
698 { vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG
699 { vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
700 { NULL, 0 },
701 { NULL, 0 },
702 { NULL, 0 },
703 { NULL, 0 },
704 { vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
705 { vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
706 { vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
707 { vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
708 { NULL, 0 },
709 { NULL, 0 },
710 { NULL, 0 },
711 { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
712 { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
713 { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
714 { NULL, 0 },
715 { NULL, 0 },
716 { NULL, 0 },
717 { NULL, 0 },
718 { NULL, 0 },
719 { NULL, 0 },
720 { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
721 { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
722 { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
723 { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
724};
725
726
727
728
729static u32
730vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
731 struct vfp_double *vdm, u32 fpscr)
732{
733 struct vfp_double *vdp;
734 u32 exceptions = 0;
735 int tn, tm;
736
737 tn = vfp_double_type(vdn);
738 tm = vfp_double_type(vdm);
739
740 if (tn & tm & VFP_INFINITY) {
741 /*
742 * Two infinities. Are they different signs?
743 */
744 if (vdn->sign ^ vdm->sign) {
745 /*
746 * different signs -> invalid
747 */
748 exceptions = FPSCR_IOC;
749 vdp = &vfp_double_default_qnan;
750 } else {
751 /*
752 * same signs -> valid
753 */
754 vdp = vdn;
755 }
756 } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
757 /*
758 * One infinity and one number -> infinity
759 */
760 vdp = vdn;
761 } else {
762 /*
763 * 'n' is a NaN of some type
764 */
765 return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
766 }
767 *vdd = *vdp;
768 return exceptions;
769}
770
771static u32
772vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,
773 struct vfp_double *vdm, u32 fpscr)
774{
775 u32 exp_diff;
776 u64 m_sig;
777
778 if (vdn->significand & (1ULL << 63) ||
779 vdm->significand & (1ULL << 63)) {
780 pr_info("VFP: bad FP values\n");
781 vfp_double_dump("VDN", vdn);
782 vfp_double_dump("VDM", vdm);
783 }
784
785 /*
786 * Ensure that 'n' is the largest magnitude number. Note that
787 * if 'n' and 'm' have equal exponents, we do not swap them.
788 * This ensures that NaN propagation works correctly.
789 */
790 if (vdn->exponent < vdm->exponent) {
791 struct vfp_double *t = vdn;
792 vdn = vdm;
793 vdm = t;
794 }
795
796 /*
797 * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
798 * infinity or a NaN here.
799 */
800 if (vdn->exponent == 2047)
801 return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
802
803 /*
804 * We have two proper numbers, where 'vdn' is the larger magnitude.
805 *
806 * Copy 'n' to 'd' before doing the arithmetic.
807 */
808 *vdd = *vdn;
809
810 /*
811 * Align 'm' with the result.
812 */
813 exp_diff = vdn->exponent - vdm->exponent;
814 m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
815
816 /*
817 * If the signs are different, we are really subtracting.
818 */
819 if (vdn->sign ^ vdm->sign) {
820 m_sig = vdn->significand - m_sig;
821 if ((s64)m_sig < 0) {
822 vdd->sign = vfp_sign_negate(vdd->sign);
823 m_sig = -m_sig;
824 } else if (m_sig == 0) {
825 vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
826 FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
827 }
828 } else {
829 m_sig += vdn->significand;
830 }
831 vdd->significand = m_sig;
832
833 return 0;
834}
835
836static u32
837vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
838 struct vfp_double *vdm, u32 fpscr)
839{
840 vfp_double_dump("VDN", vdn);
841 vfp_double_dump("VDM", vdm);
842
843 /*
844 * Ensure that 'n' is the largest magnitude number. Note that
845 * if 'n' and 'm' have equal exponents, we do not swap them.
846 * This ensures that NaN propagation works correctly.
847 */
848 if (vdn->exponent < vdm->exponent) {
849 struct vfp_double *t = vdn;
850 vdn = vdm;
851 vdm = t;
852 pr_debug("VFP: swapping M <-> N\n");
853 }
854
855 vdd->sign = vdn->sign ^ vdm->sign;
856
857 /*
858 * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
859 */
860 if (vdn->exponent == 2047) {
861 if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
862 return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
863 if ((vdm->exponent | vdm->significand) == 0) {
864 *vdd = vfp_double_default_qnan;
865 return FPSCR_IOC;
866 }
867 vdd->exponent = vdn->exponent;
868 vdd->significand = 0;
869 return 0;
870 }
871
872 /*
873 * If 'm' is zero, the result is always zero. In this case,
874 * 'n' may be zero or a number, but it doesn't matter which.
875 */
876 if ((vdm->exponent | vdm->significand) == 0) {
877 vdd->exponent = 0;
878 vdd->significand = 0;
879 return 0;
880 }
881
882 /*
883 * We add 2 to the destination exponent for the same reason
884 * as the addition case - though this time we have +1 from
885 * each input operand.
886 */
887 vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
888 vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
889
890 vfp_double_dump("VDD", vdd);
891 return 0;
892}
893
894#define NEG_MULTIPLY (1 << 0)
895#define NEG_SUBTRACT (1 << 1)
896
897static u32
898vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func)
899{
900 struct vfp_double vdd, vdp, vdn, vdm;
901 u32 exceptions;
902
903 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
904 if (vdn.exponent == 0 && vdn.significand)
905 vfp_double_normalise_denormal(&vdn);
906
907 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
908 if (vdm.exponent == 0 && vdm.significand)
909 vfp_double_normalise_denormal(&vdm);
910
911 exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
912 if (negate & NEG_MULTIPLY)
913 vdp.sign = vfp_sign_negate(vdp.sign);
914
915 vfp_double_unpack(&vdn, vfp_get_double(state, dd));
916 if (negate & NEG_SUBTRACT)
917 vdn.sign = vfp_sign_negate(vdn.sign);
918
919 exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
920
921 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func);
922}
923
924/*
925 * Standard operations
926 */
927
928/*
929 * sd = sd + (sn * sm)
930 */
931static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
932{
933 pr_debug("In %s\n", __FUNCTION__);
934 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac");
935}
936
937/*
938 * sd = sd - (sn * sm)
939 */
940static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
941{
942 pr_debug("In %s\n", __FUNCTION__);
943 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
944}
945
946/*
947 * sd = -sd + (sn * sm)
948 */
949static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
950{
951 pr_debug("In %s\n", __FUNCTION__);
952 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
953}
954
955/*
956 * sd = -sd - (sn * sm)
957 */
958static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
959{
960 pr_debug("In %s\n", __FUNCTION__);
961 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
962}
963
964/*
965 * sd = sn * sm
966 */
967static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
968{
969 struct vfp_double vdd, vdn, vdm;
970 u32 exceptions;
971
972 pr_debug("In %s\n", __FUNCTION__);
973 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
974 if (vdn.exponent == 0 && vdn.significand)
975 vfp_double_normalise_denormal(&vdn);
976
977 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
978 if (vdm.exponent == 0 && vdm.significand)
979 vfp_double_normalise_denormal(&vdm);
980
981 exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
982 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul");
983}
984
985/*
986 * sd = -(sn * sm)
987 */
988static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
989{
990 struct vfp_double vdd, vdn, vdm;
991 u32 exceptions;
992
993 pr_debug("In %s\n", __FUNCTION__);
994 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
995 if (vdn.exponent == 0 && vdn.significand)
996 vfp_double_normalise_denormal(&vdn);
997
998 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
999 if (vdm.exponent == 0 && vdm.significand)
1000 vfp_double_normalise_denormal(&vdm);
1001
1002 exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
1003 vdd.sign = vfp_sign_negate(vdd.sign);
1004
1005 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul");
1006}
1007
1008/*
1009 * sd = sn + sm
1010 */
1011static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1012{
1013 struct vfp_double vdd, vdn, vdm;
1014 u32 exceptions;
1015
1016 pr_debug("In %s\n", __FUNCTION__);
1017 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1018 if (vdn.exponent == 0 && vdn.significand)
1019 vfp_double_normalise_denormal(&vdn);
1020
1021 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1022 if (vdm.exponent == 0 && vdm.significand)
1023 vfp_double_normalise_denormal(&vdm);
1024
1025 exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
1026
1027 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd");
1028}
1029
1030/*
1031 * sd = sn - sm
1032 */
1033static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1034{
1035 struct vfp_double vdd, vdn, vdm;
1036 u32 exceptions;
1037
1038 pr_debug("In %s\n", __FUNCTION__);
1039 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1040 if (vdn.exponent == 0 && vdn.significand)
1041 vfp_double_normalise_denormal(&vdn);
1042
1043 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1044 if (vdm.exponent == 0 && vdm.significand)
1045 vfp_double_normalise_denormal(&vdm);
1046
1047 /*
1048 * Subtraction is like addition, but with a negated operand.
1049 */
1050 vdm.sign = vfp_sign_negate(vdm.sign);
1051
1052 exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
1053
1054 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub");
1055}
1056
1057/*
1058 * sd = sn / sm
1059 */
1060static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1061{
1062 struct vfp_double vdd, vdn, vdm;
1063 u32 exceptions = 0;
1064 int tm, tn;
1065
1066 pr_debug("In %s\n", __FUNCTION__);
1067 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1068 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1069
1070 vdd.sign = vdn.sign ^ vdm.sign;
1071
1072 tn = vfp_double_type(&vdn);
1073 tm = vfp_double_type(&vdm);
1074
1075 /*
1076 * Is n a NAN?
1077 */
1078 if (tn & VFP_NAN)
1079 goto vdn_nan;
1080
1081 /*
1082 * Is m a NAN?
1083 */
1084 if (tm & VFP_NAN)
1085 goto vdm_nan;
1086
1087 /*
1088 * If n and m are infinity, the result is invalid
1089 * If n and m are zero, the result is invalid
1090 */
1091 if (tm & tn & (VFP_INFINITY|VFP_ZERO))
1092 goto invalid;
1093
1094 /*
1095 * If n is infinity, the result is infinity
1096 */
1097 if (tn & VFP_INFINITY)
1098 goto infinity;
1099
1100 /*
1101 * If m is zero, raise div0 exceptions
1102 */
1103 if (tm & VFP_ZERO)
1104 goto divzero;
1105
1106 /*
1107 * If m is infinity, or n is zero, the result is zero
1108 */
1109 if (tm & VFP_INFINITY || tn & VFP_ZERO)
1110 goto zero;
1111
1112 if (tn & VFP_DENORMAL)
1113 vfp_double_normalise_denormal(&vdn);
1114 if (tm & VFP_DENORMAL)
1115 vfp_double_normalise_denormal(&vdm);
1116
1117 /*
1118 * Ok, we have two numbers, we can perform division.
1119 */
1120 vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
1121 vdm.significand <<= 1;
1122 if (vdm.significand <= (2 * vdn.significand)) {
1123 vdn.significand >>= 1;
1124 vdd.exponent++;
1125 }
1126 vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
1127 if ((vdd.significand & 0x1ff) <= 2) {
1128 u64 termh, terml, remh, reml;
1129 mul64to128(&termh, &terml, vdm.significand, vdd.significand);
1130 sub128(&remh, &reml, vdn.significand, 0, termh, terml);
1131 while ((s64)remh < 0) {
1132 vdd.significand -= 1;
1133 add128(&remh, &reml, remh, reml, 0, vdm.significand);
1134 }
1135 vdd.significand |= (reml != 0);
1136 }
1137 return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
1138
1139 vdn_nan:
1140 exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
1141 pack:
1142 vfp_put_double(state, vfp_double_pack(&vdd), dd);
1143 return exceptions;
1144
1145 vdm_nan:
1146 exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
1147 goto pack;
1148
1149 zero:
1150 vdd.exponent = 0;
1151 vdd.significand = 0;
1152 goto pack;
1153
1154 divzero:
1155 exceptions = FPSCR_DZC;
1156 infinity:
1157 vdd.exponent = 2047;
1158 vdd.significand = 0;
1159 goto pack;
1160
1161 invalid:
1162 vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
1163 return FPSCR_IOC;
1164}
1165
1166static struct op fops[] = {
1167 { vfp_double_fmac, 0 },
1168 { vfp_double_fmsc, 0 },
1169 { vfp_double_fmul, 0 },
1170 { vfp_double_fadd, 0 },
1171 { vfp_double_fnmac, 0 },
1172 { vfp_double_fnmsc, 0 },
1173 { vfp_double_fnmul, 0 },
1174 { vfp_double_fsub, 0 },
1175 { vfp_double_fdiv, 0 },
1176};
1177
1178#define FREG_BANK(x) ((x) & 0x0c)
1179#define FREG_IDX(x) ((x) & 3)
1180
1181u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
1182{
1183 u32 op = inst & FOP_MASK;
1184 u32 exceptions = 0;
1185 unsigned int dest;
1186 unsigned int dn = vfp_get_dn(inst);
1187 unsigned int dm;
1188 unsigned int vecitr, veclen, vecstride;
1189 struct op *fop;
1190
1191 pr_debug("In %s\n", __FUNCTION__);
1192 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
1193
1194 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1195
1196 /*
1197 * fcvtds takes an sN register number as destination, not dN.
1198 * It also always operates on scalars.
1199 */
1200 if (fop->flags & OP_SD)
1201 dest = vfp_get_sd(inst);
1202 else
1203 dest = vfp_get_dd(inst);
1204
1205 /*
1206 * f[us]ito takes a sN operand, not a dN operand.
1207 */
1208 if (fop->flags & OP_SM)
1209 dm = vfp_get_sm(inst);
1210 else
1211 dm = vfp_get_dm(inst);
1212
1213 /*
1214 * If destination bank is zero, vector length is always '1'.
1215 * ARM DDI0100F C5.1.3, C5.3.2.
1216 */
1217 if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
1218 veclen = 0;
1219 else
1220 veclen = fpscr & FPSCR_LENGTH_MASK;
1221
1222 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1223 (veclen >> FPSCR_LENGTH_BIT) + 1);
1224
1225 if (!fop->fn) {
1226 printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst));
1227 goto invalid;
1228 }
1229
1230 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1231 u32 except;
1232 char type;
1233
1234 type = fop->flags & OP_SD ? 's' : 'd';
1235 if (op == FOP_EXT)
1236 pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
1237 vecitr >> FPSCR_LENGTH_BIT,
1238 type, dest, dn, dm);
1239 else
1240 pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
1241 vecitr >> FPSCR_LENGTH_BIT,
1242 type, dest, dn, FOP_TO_IDX(op), dm);
1243
1244 except = fop->fn(state, dest, dn, dm, fpscr);
1245 pr_debug("VFP: itr%d: exceptions=%08x\n",
1246 vecitr >> FPSCR_LENGTH_BIT, except);
1247
1248 exceptions |= except;
1249
1250 /*
1251 * CHECK: It appears to be undefined whether we stop when
1252 * we encounter an exception. We continue.
1253 */
1254 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
1255 dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
1256 if (FREG_BANK(dm) != 0)
1257 dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
1258 }
1259 return exceptions;
1260
1261 invalid:
1262 return ~0;
1263}
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 @@
1/*
2 vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * This code is derived in part from :
23 * - Android kernel
24 * - John R. Housers softfloat library, which
25 * carries the following notice:
26 *
27 * ===========================================================================
28 * This C source file is part of the SoftFloat IEC/IEEE Floating-point
29 * Arithmetic Package, Release 2.
30 *
31 * Written by John R. Hauser. This work was made possible in part by the
32 * International Computer Science Institute, located at Suite 600, 1947 Center
33 * Street, Berkeley, California 94704. Funding was partially provided by the
34 * National Science Foundation under grant MIP-9311980. The original version
35 * of this code was written as part of a project to build a fixed-point vector
36 * processor in collaboration with the University of California at Berkeley,
37 * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
38 * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
39 * arithmetic/softfloat.html'.
40 *
41 * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
42 * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
43 * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
44 * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
45 * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
46 *
47 * Derivative works are acceptable, even for commercial purposes, so long as
48 * (1) they include prominent notice that the work is derivative, and (2) they
49 * include prominent notice akin to these three paragraphs for those parts of
50 * this code that are retained.
51 * ===========================================================================
52 */
53
54#include "core/arm/interpreter/vfp/vfp_helper.h"
55#include "core/arm/interpreter/vfp/asm_vfp.h"
56#include "core/arm/interpreter/vfp/vfp.h"
57
58static struct vfp_single vfp_single_default_qnan = {
59 //.exponent = 255,
60 //.sign = 0,
61 //.significand = VFP_SINGLE_SIGNIFICAND_QNAN,
62};
63
64static void vfp_single_dump(const char *str, struct vfp_single *s)
65{
66 pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
67 str, s->sign != 0, s->exponent, s->significand);
68}
69
70static void vfp_single_normalise_denormal(struct vfp_single *vs)
71{
72 int bits = 31 - vfp_fls(vs->significand);
73
74 vfp_single_dump("normalise_denormal: in", vs);
75
76 if (bits) {
77 vs->exponent -= bits - 1;
78 vs->significand <<= bits;
79 }
80
81 vfp_single_dump("normalise_denormal: out", vs);
82}
83
84
85u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func)
86{
87 u32 significand, incr, rmode;
88 int exponent, shift, underflow;
89
90 vfp_single_dump("pack: in", vs);
91
92 /*
93 * Infinities and NaNs are a special case.
94 */
95 if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
96 goto pack;
97
98 /*
99 * Special-case zero.
100 */
101 if (vs->significand == 0) {
102 vs->exponent = 0;
103 goto pack;
104 }
105
106 exponent = vs->exponent;
107 significand = vs->significand;
108
109 /*
110 * Normalise first. Note that we shift the significand up to
111 * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
112 * significant bit.
113 */
114 shift = 32 - vfp_fls(significand);
115 if (shift < 32 && shift) {
116 exponent -= shift;
117 significand <<= shift;
118 }
119
120#if 1
121 vs->exponent = exponent;
122 vs->significand = significand;
123 vfp_single_dump("pack: normalised", vs);
124#endif
125
126 /*
127 * Tiny number?
128 */
129 underflow = exponent < 0;
130 if (underflow) {
131 significand = vfp_shiftright32jamming(significand, -exponent);
132 exponent = 0;
133#if 1
134 vs->exponent = exponent;
135 vs->significand = significand;
136 vfp_single_dump("pack: tiny number", vs);
137#endif
138 if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
139 underflow = 0;
140 }
141
142 /*
143 * Select rounding increment.
144 */
145 incr = 0;
146 rmode = fpscr & FPSCR_RMODE_MASK;
147
148 if (rmode == FPSCR_ROUND_NEAREST) {
149 incr = 1 << VFP_SINGLE_LOW_BITS;
150 if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
151 incr -= 1;
152 } else if (rmode == FPSCR_ROUND_TOZERO) {
153 incr = 0;
154 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
155 incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
156
157 pr_debug("VFP: rounding increment = 0x%08x\n", incr);
158
159 /*
160 * Is our rounding going to overflow?
161 */
162 if ((significand + incr) < significand) {
163 exponent += 1;
164 significand = (significand >> 1) | (significand & 1);
165 incr >>= 1;
166#if 1
167 vs->exponent = exponent;
168 vs->significand = significand;
169 vfp_single_dump("pack: overflow", vs);
170#endif
171 }
172
173 /*
174 * If any of the low bits (which will be shifted out of the
175 * number) are non-zero, the result is inexact.
176 */
177 if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
178 exceptions |= FPSCR_IXC;
179
180 /*
181 * Do our rounding.
182 */
183 significand += incr;
184
185 /*
186 * Infinity?
187 */
188 if (exponent >= 254) {
189 exceptions |= FPSCR_OFC | FPSCR_IXC;
190 if (incr == 0) {
191 vs->exponent = 253;
192 vs->significand = 0x7fffffff;
193 } else {
194 vs->exponent = 255; /* infinity */
195 vs->significand = 0;
196 }
197 } else {
198 if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
199 exponent = 0;
200 if (exponent || significand > 0x80000000)
201 underflow = 0;
202 if (underflow)
203 exceptions |= FPSCR_UFC;
204 vs->exponent = exponent;
205 vs->significand = significand >> 1;
206 }
207
208 pack:
209 vfp_single_dump("pack: final", vs);
210 {
211 s32 d = vfp_single_pack(vs);
212#if 1
213 pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
214 sd, d, exceptions);
215#endif
216 vfp_put_float(state, d, sd);
217 }
218
219 return exceptions;
220}
221
222/*
223 * Propagate the NaN, setting exceptions if it is signalling.
224 * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
225 */
226static u32
227vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
228 struct vfp_single *vsm, u32 fpscr)
229{
230 struct vfp_single *nan;
231 int tn, tm = 0;
232
233 tn = vfp_single_type(vsn);
234
235 if (vsm)
236 tm = vfp_single_type(vsm);
237
238 if (fpscr & FPSCR_DEFAULT_NAN)
239 /*
240 * Default NaN mode - always returns a quiet NaN
241 */
242 nan = &vfp_single_default_qnan;
243 else {
244 /*
245 * Contemporary mode - select the first signalling
246 * NAN, or if neither are signalling, the first
247 * quiet NAN.
248 */
249 if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
250 nan = vsn;
251 else
252 nan = vsm;
253 /*
254 * Make the NaN quiet.
255 */
256 nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
257 }
258
259 *vsd = *nan;
260
261 /*
262 * If one was a signalling NAN, raise invalid operation.
263 */
264 return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
265}
266
267
268/*
269 * Extended operations
270 */
271static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
272{
273 vfp_put_float(state, vfp_single_packed_abs(m), sd);
274 return 0;
275}
276
277static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
278{
279 vfp_put_float(state, m, sd);
280 return 0;
281}
282
283static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
284{
285 vfp_put_float(state, vfp_single_packed_negate(m), sd);
286 return 0;
287}
288
289static const u16 sqrt_oddadjust[] = {
290 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
291 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
292};
293
294static const u16 sqrt_evenadjust[] = {
295 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
296 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
297};
298
299u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
300{
301 int index;
302 u32 z, a;
303
304 if ((significand & 0xc0000000) != 0x40000000) {
305 pr_debug("VFP: estimate_sqrt: invalid significand\n");
306 }
307
308 a = significand << 1;
309 index = (a >> 27) & 15;
310 if (exponent & 1) {
311 z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
312 z = ((a / z) << 14) + (z << 15);
313 a >>= 1;
314 } else {
315 z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
316 z = a / z + z;
317 z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
318 if (z <= a)
319 return (s32)a >> 1;
320 }
321 {
322 u64 v = (u64)a << 31;
323 do_div(v, z);
324 return v + (z >> 1);
325 }
326}
327
328static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
329{
330 struct vfp_single vsm, vsd, *vsp;
331 int ret, tm;
332
333 vfp_single_unpack(&vsm, m);
334 tm = vfp_single_type(&vsm);
335 if (tm & (VFP_NAN|VFP_INFINITY)) {
336 vsp = &vsd;
337
338 if (tm & VFP_NAN)
339 ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
340 else if (vsm.sign == 0) {
341 sqrt_copy:
342 vsp = &vsm;
343 ret = 0;
344 } else {
345 sqrt_invalid:
346 vsp = &vfp_single_default_qnan;
347 ret = FPSCR_IOC;
348 }
349 vfp_put_float(state, vfp_single_pack(vsp), sd);
350 return ret;
351 }
352
353 /*
354 * sqrt(+/- 0) == +/- 0
355 */
356 if (tm & VFP_ZERO)
357 goto sqrt_copy;
358
359 /*
360 * Normalise a denormalised number
361 */
362 if (tm & VFP_DENORMAL)
363 vfp_single_normalise_denormal(&vsm);
364
365 /*
366 * sqrt(<0) = invalid
367 */
368 if (vsm.sign)
369 goto sqrt_invalid;
370
371 vfp_single_dump("sqrt", &vsm);
372
373 /*
374 * Estimate the square root.
375 */
376 vsd.sign = 0;
377 vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
378 vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
379
380 vfp_single_dump("sqrt estimate", &vsd);
381
382 /*
383 * And now adjust.
384 */
385 if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
386 if (vsd.significand < 2) {
387 vsd.significand = 0xffffffff;
388 } else {
389 u64 term;
390 s64 rem;
391 vsm.significand <<= !(vsm.exponent & 1);
392 term = (u64)vsd.significand * vsd.significand;
393 rem = ((u64)vsm.significand << 32) - term;
394
395 pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
396
397 while (rem < 0) {
398 vsd.significand -= 1;
399 rem += ((u64)vsd.significand << 1) | 1;
400 }
401 vsd.significand |= rem != 0;
402 }
403 }
404 vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
405
406 return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt");
407}
408
409/*
410 * Equal := ZC
411 * Less than := N
412 * Greater than := C
413 * Unordered := CV
414 */
415static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr)
416{
417 s32 d;
418 u32 ret = 0;
419
420 d = vfp_get_float(state, sd);
421 if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
422 ret |= FPSCR_C | FPSCR_V;
423 if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
424 /*
425 * Signalling NaN, or signalling on quiet NaN
426 */
427 ret |= FPSCR_IOC;
428 }
429
430 if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
431 ret |= FPSCR_C | FPSCR_V;
432 if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
433 /*
434 * Signalling NaN, or signalling on quiet NaN
435 */
436 ret |= FPSCR_IOC;
437 }
438
439 if (ret == 0) {
440 if (d == m || vfp_single_packed_abs(d | m) == 0) {
441 /*
442 * equal
443 */
444 ret |= FPSCR_Z | FPSCR_C;
445 } else if (vfp_single_packed_sign(d ^ m)) {
446 /*
447 * different signs
448 */
449 if (vfp_single_packed_sign(d))
450 /*
451 * d is negative, so d < m
452 */
453 ret |= FPSCR_N;
454 else
455 /*
456 * d is positive, so d > m
457 */
458 ret |= FPSCR_C;
459 } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
460 /*
461 * d < m
462 */
463 ret |= FPSCR_N;
464 } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
465 /*
466 * d > m
467 */
468 ret |= FPSCR_C;
469 }
470 }
471 return ret;
472}
473
474static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
475{
476 return vfp_compare(state, sd, 0, m, fpscr);
477}
478
479static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
480{
481 return vfp_compare(state, sd, 1, m, fpscr);
482}
483
484static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
485{
486 return vfp_compare(state, sd, 0, 0, fpscr);
487}
488
489static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
490{
491 return vfp_compare(state, sd, 1, 0, fpscr);
492}
493
494static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr)
495{
496 struct vfp_single vsm;
497 struct vfp_double vdd;
498 int tm;
499 u32 exceptions = 0;
500
501 vfp_single_unpack(&vsm, m);
502
503 tm = vfp_single_type(&vsm);
504
505 /*
506 * If we have a signalling NaN, signal invalid operation.
507 */
508 if (tm == VFP_SNAN)
509 exceptions = FPSCR_IOC;
510
511 if (tm & VFP_DENORMAL)
512 vfp_single_normalise_denormal(&vsm);
513
514 vdd.sign = vsm.sign;
515 vdd.significand = (u64)vsm.significand << 32;
516
517 /*
518 * If we have an infinity or NaN, the exponent must be 2047.
519 */
520 if (tm & (VFP_INFINITY|VFP_NAN)) {
521 vdd.exponent = 2047;
522 if (tm == VFP_QNAN)
523 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
524 goto pack_nan;
525 } else if (tm & VFP_ZERO)
526 vdd.exponent = 0;
527 else
528 vdd.exponent = vsm.exponent + (1023 - 127);
529
530 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
531
532 pack_nan:
533 vfp_put_double(state, vfp_double_pack(&vdd), dd);
534 return exceptions;
535}
536
537static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
538{
539 struct vfp_single vs;
540
541 vs.sign = 0;
542 vs.exponent = 127 + 31 - 1;
543 vs.significand = (u32)m;
544
545 return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito");
546}
547
548static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
549{
550 struct vfp_single vs;
551
552 vs.sign = (m & 0x80000000) >> 16;
553 vs.exponent = 127 + 31 - 1;
554 vs.significand = vs.sign ? -m : m;
555
556 return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito");
557}
558
559static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
560{
561 struct vfp_single vsm;
562 u32 d, exceptions = 0;
563 int rmode = fpscr & FPSCR_RMODE_MASK;
564 int tm;
565
566 vfp_single_unpack(&vsm, m);
567 vfp_single_dump("VSM", &vsm);
568
569 /*
570 * Do we have a denormalised number?
571 */
572 tm = vfp_single_type(&vsm);
573 if (tm & VFP_DENORMAL)
574 exceptions |= FPSCR_IDC;
575
576 if (tm & VFP_NAN)
577 vsm.sign = 0;
578
579 if (vsm.exponent >= 127 + 32) {
580 d = vsm.sign ? 0 : 0xffffffff;
581 exceptions = FPSCR_IOC;
582 } else if (vsm.exponent >= 127 - 1) {
583 int shift = 127 + 31 - vsm.exponent;
584 u32 rem, incr = 0;
585
586 /*
587 * 2^0 <= m < 2^32-2^8
588 */
589 d = (vsm.significand << 1) >> shift;
590 rem = vsm.significand << (33 - shift);
591
592 if (rmode == FPSCR_ROUND_NEAREST) {
593 incr = 0x80000000;
594 if ((d & 1) == 0)
595 incr -= 1;
596 } else if (rmode == FPSCR_ROUND_TOZERO) {
597 incr = 0;
598 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
599 incr = ~0;
600 }
601
602 if ((rem + incr) < rem) {
603 if (d < 0xffffffff)
604 d += 1;
605 else
606 exceptions |= FPSCR_IOC;
607 }
608
609 if (d && vsm.sign) {
610 d = 0;
611 exceptions |= FPSCR_IOC;
612 } else if (rem)
613 exceptions |= FPSCR_IXC;
614 } else {
615 d = 0;
616 if (vsm.exponent | vsm.significand) {
617 exceptions |= FPSCR_IXC;
618 if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
619 d = 1;
620 else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
621 d = 0;
622 exceptions |= FPSCR_IOC;
623 }
624 }
625 }
626
627 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
628
629 vfp_put_float(state, d, sd);
630
631 return exceptions;
632}
633
634static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
635{
636 return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO);
637}
638
639static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
640{
641 struct vfp_single vsm;
642 u32 d, exceptions = 0;
643 int rmode = fpscr & FPSCR_RMODE_MASK;
644 int tm;
645
646 vfp_single_unpack(&vsm, m);
647 vfp_single_dump("VSM", &vsm);
648
649 /*
650 * Do we have a denormalised number?
651 */
652 tm = vfp_single_type(&vsm);
653 if (vfp_single_type(&vsm) & VFP_DENORMAL)
654 exceptions |= FPSCR_IDC;
655
656 if (tm & VFP_NAN) {
657 d = 0;
658 exceptions |= FPSCR_IOC;
659 } else if (vsm.exponent >= 127 + 32) {
660 /*
661 * m >= 2^31-2^7: invalid
662 */
663 d = 0x7fffffff;
664 if (vsm.sign)
665 d = ~d;
666 exceptions |= FPSCR_IOC;
667 } else if (vsm.exponent >= 127 - 1) {
668 int shift = 127 + 31 - vsm.exponent;
669 u32 rem, incr = 0;
670
671 /* 2^0 <= m <= 2^31-2^7 */
672 d = (vsm.significand << 1) >> shift;
673 rem = vsm.significand << (33 - shift);
674
675 if (rmode == FPSCR_ROUND_NEAREST) {
676 incr = 0x80000000;
677 if ((d & 1) == 0)
678 incr -= 1;
679 } else if (rmode == FPSCR_ROUND_TOZERO) {
680 incr = 0;
681 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
682 incr = ~0;
683 }
684
685 if ((rem + incr) < rem && d < 0xffffffff)
686 d += 1;
687 if (d > 0x7fffffff + (vsm.sign != 0)) {
688 d = 0x7fffffff + (vsm.sign != 0);
689 exceptions |= FPSCR_IOC;
690 } else if (rem)
691 exceptions |= FPSCR_IXC;
692
693 if (vsm.sign)
694 d = -d;
695 } else {
696 d = 0;
697 if (vsm.exponent | vsm.significand) {
698 exceptions |= FPSCR_IXC;
699 if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
700 d = 1;
701 else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign)
702 d = -1;
703 }
704 }
705
706 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
707
708 vfp_put_float(state, (s32)d, sd);
709
710 return exceptions;
711}
712
713static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
714{
715 return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO);
716}
717
718static struct op fops_ext[] = {
719 { vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY
720 { vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS
721 { vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG
722 { vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
723 { NULL, 0 },
724 { NULL, 0 },
725 { NULL, 0 },
726 { NULL, 0 },
727 { vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
728 { vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
729 { vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
730 { vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
731 { NULL, 0 },
732 { NULL, 0 },
733 { NULL, 0 },
734 { vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
735 { vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
736 { vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
737 { NULL, 0 },
738 { NULL, 0 },
739 { NULL, 0 },
740 { NULL, 0 },
741 { NULL, 0 },
742 { NULL, 0 },
743 { vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
744 { vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
745 { vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
746 { vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
747};
748
749
750
751
752
753static u32
754vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
755 struct vfp_single *vsm, u32 fpscr)
756{
757 struct vfp_single *vsp;
758 u32 exceptions = 0;
759 int tn, tm;
760
761 tn = vfp_single_type(vsn);
762 tm = vfp_single_type(vsm);
763
764 if (tn & tm & VFP_INFINITY) {
765 /*
766 * Two infinities. Are they different signs?
767 */
768 if (vsn->sign ^ vsm->sign) {
769 /*
770 * different signs -> invalid
771 */
772 exceptions = FPSCR_IOC;
773 vsp = &vfp_single_default_qnan;
774 } else {
775 /*
776 * same signs -> valid
777 */
778 vsp = vsn;
779 }
780 } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
781 /*
782 * One infinity and one number -> infinity
783 */
784 vsp = vsn;
785 } else {
786 /*
787 * 'n' is a NaN of some type
788 */
789 return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
790 }
791 *vsd = *vsp;
792 return exceptions;
793}
794
795static u32
796vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
797 struct vfp_single *vsm, u32 fpscr)
798{
799 u32 exp_diff, m_sig;
800
801 if (vsn->significand & 0x80000000 ||
802 vsm->significand & 0x80000000) {
803 pr_info("VFP: bad FP values\n");
804 vfp_single_dump("VSN", vsn);
805 vfp_single_dump("VSM", vsm);
806 }
807
808 /*
809 * Ensure that 'n' is the largest magnitude number. Note that
810 * if 'n' and 'm' have equal exponents, we do not swap them.
811 * This ensures that NaN propagation works correctly.
812 */
813 if (vsn->exponent < vsm->exponent) {
814 struct vfp_single *t = vsn;
815 vsn = vsm;
816 vsm = t;
817 }
818
819 /*
820 * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
821 * infinity or a NaN here.
822 */
823 if (vsn->exponent == 255)
824 return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
825
826 /*
827 * We have two proper numbers, where 'vsn' is the larger magnitude.
828 *
829 * Copy 'n' to 'd' before doing the arithmetic.
830 */
831 *vsd = *vsn;
832
833 /*
834 * Align both numbers.
835 */
836 exp_diff = vsn->exponent - vsm->exponent;
837 m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
838
839 /*
840 * If the signs are different, we are really subtracting.
841 */
842 if (vsn->sign ^ vsm->sign) {
843 m_sig = vsn->significand - m_sig;
844 if ((s32)m_sig < 0) {
845 vsd->sign = vfp_sign_negate(vsd->sign);
846 m_sig = -m_sig;
847 } else if (m_sig == 0) {
848 vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
849 FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
850 }
851 } else {
852 m_sig = vsn->significand + m_sig;
853 }
854 vsd->significand = m_sig;
855
856 return 0;
857}
858
859static u32
860vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
861{
862 vfp_single_dump("VSN", vsn);
863 vfp_single_dump("VSM", vsm);
864
865 /*
866 * Ensure that 'n' is the largest magnitude number. Note that
867 * if 'n' and 'm' have equal exponents, we do not swap them.
868 * This ensures that NaN propagation works correctly.
869 */
870 if (vsn->exponent < vsm->exponent) {
871 struct vfp_single *t = vsn;
872 vsn = vsm;
873 vsm = t;
874 pr_debug("VFP: swapping M <-> N\n");
875 }
876
877 vsd->sign = vsn->sign ^ vsm->sign;
878
879 /*
880 * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
881 */
882 if (vsn->exponent == 255) {
883 if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
884 return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
885 if ((vsm->exponent | vsm->significand) == 0) {
886 *vsd = vfp_single_default_qnan;
887 return FPSCR_IOC;
888 }
889 vsd->exponent = vsn->exponent;
890 vsd->significand = 0;
891 return 0;
892 }
893
894 /*
895 * If 'm' is zero, the result is always zero. In this case,
896 * 'n' may be zero or a number, but it doesn't matter which.
897 */
898 if ((vsm->exponent | vsm->significand) == 0) {
899 vsd->exponent = 0;
900 vsd->significand = 0;
901 return 0;
902 }
903
904 /*
905 * We add 2 to the destination exponent for the same reason as
906 * the addition case - though this time we have +1 from each
907 * input operand.
908 */
909 vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
910 vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
911
912 vfp_single_dump("VSD", vsd);
913 return 0;
914}
915
916#define NEG_MULTIPLY (1 << 0)
917#define NEG_SUBTRACT (1 << 1)
918
919static u32
920vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func)
921{
922 struct vfp_single vsd, vsp, vsn, vsm;
923 u32 exceptions;
924 s32 v;
925
926 v = vfp_get_float(state, sn);
927 pr_debug("VFP: s%u = %08x\n", sn, v);
928 vfp_single_unpack(&vsn, v);
929 if (vsn.exponent == 0 && vsn.significand)
930 vfp_single_normalise_denormal(&vsn);
931
932 vfp_single_unpack(&vsm, m);
933 if (vsm.exponent == 0 && vsm.significand)
934 vfp_single_normalise_denormal(&vsm);
935
936 exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
937 if (negate & NEG_MULTIPLY)
938 vsp.sign = vfp_sign_negate(vsp.sign);
939
940 v = vfp_get_float(state, sd);
941 pr_debug("VFP: s%u = %08x\n", sd, v);
942 vfp_single_unpack(&vsn, v);
943 if (negate & NEG_SUBTRACT)
944 vsn.sign = vfp_sign_negate(vsn.sign);
945
946 exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
947
948 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
949}
950
951/*
952 * Standard operations
953 */
954
955/*
956 * sd = sd + (sn * sm)
957 */
958static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
959{
960 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
961 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
962}
963
964/*
965 * sd = sd - (sn * sm)
966 */
967static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
968{
969 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn);
970 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
971}
972
973/*
974 * sd = -sd + (sn * sm)
975 */
976static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
977{
978 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
979 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
980}
981
982/*
983 * sd = -sd - (sn * sm)
984 */
985static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
986{
987 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
988 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
989}
990
991/*
992 * sd = sn * sm
993 */
994static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
995{
996 struct vfp_single vsd, vsn, vsm;
997 u32 exceptions;
998 s32 n = vfp_get_float(state, sn);
999
1000 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n);
1001
1002 vfp_single_unpack(&vsn, n);
1003 if (vsn.exponent == 0 && vsn.significand)
1004 vfp_single_normalise_denormal(&vsn);
1005
1006 vfp_single_unpack(&vsm, m);
1007 if (vsm.exponent == 0 && vsm.significand)
1008 vfp_single_normalise_denormal(&vsm);
1009
1010 exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
1011 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul");
1012}
1013
1014/*
1015 * sd = -(sn * sm)
1016 */
1017static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1018{
1019 struct vfp_single vsd, vsn, vsm;
1020 u32 exceptions;
1021 s32 n = vfp_get_float(state, sn);
1022
1023 pr_debug("VFP: s%u = %08x\n", sn, n);
1024
1025 vfp_single_unpack(&vsn, n);
1026 if (vsn.exponent == 0 && vsn.significand)
1027 vfp_single_normalise_denormal(&vsn);
1028
1029 vfp_single_unpack(&vsm, m);
1030 if (vsm.exponent == 0 && vsm.significand)
1031 vfp_single_normalise_denormal(&vsm);
1032
1033 exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
1034 vsd.sign = vfp_sign_negate(vsd.sign);
1035 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul");
1036}
1037
1038/*
1039 * sd = sn + sm
1040 */
1041static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1042{
1043 struct vfp_single vsd, vsn, vsm;
1044 u32 exceptions;
1045 s32 n = vfp_get_float(state, sn);
1046
1047 pr_debug("VFP: s%u = %08x\n", sn, n);
1048
1049 /*
1050 * Unpack and normalise denormals.
1051 */
1052 vfp_single_unpack(&vsn, n);
1053 if (vsn.exponent == 0 && vsn.significand)
1054 vfp_single_normalise_denormal(&vsn);
1055
1056 vfp_single_unpack(&vsm, m);
1057 if (vsm.exponent == 0 && vsm.significand)
1058 vfp_single_normalise_denormal(&vsm);
1059
1060 exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr);
1061
1062 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd");
1063}
1064
1065/*
1066 * sd = sn - sm
1067 */
1068static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1069{
1070 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
1071 /*
1072 * Subtraction is addition with one sign inverted.
1073 */
1074 return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr);
1075}
1076
1077/*
1078 * sd = sn / sm
1079 */
1080static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1081{
1082 struct vfp_single vsd, vsn, vsm;
1083 u32 exceptions = 0;
1084 s32 n = vfp_get_float(state, sn);
1085 int tm, tn;
1086
1087 pr_debug("VFP: s%u = %08x\n", sn, n);
1088
1089 vfp_single_unpack(&vsn, n);
1090 vfp_single_unpack(&vsm, m);
1091
1092 vsd.sign = vsn.sign ^ vsm.sign;
1093
1094 tn = vfp_single_type(&vsn);
1095 tm = vfp_single_type(&vsm);
1096
1097 /*
1098 * Is n a NAN?
1099 */
1100 if (tn & VFP_NAN)
1101 goto vsn_nan;
1102
1103 /*
1104 * Is m a NAN?
1105 */
1106 if (tm & VFP_NAN)
1107 goto vsm_nan;
1108
1109 /*
1110 * If n and m are infinity, the result is invalid
1111 * If n and m are zero, the result is invalid
1112 */
1113 if (tm & tn & (VFP_INFINITY|VFP_ZERO))
1114 goto invalid;
1115
1116 /*
1117 * If n is infinity, the result is infinity
1118 */
1119 if (tn & VFP_INFINITY)
1120 goto infinity;
1121
1122 /*
1123 * If m is zero, raise div0 exception
1124 */
1125 if (tm & VFP_ZERO)
1126 goto divzero;
1127
1128 /*
1129 * If m is infinity, or n is zero, the result is zero
1130 */
1131 if (tm & VFP_INFINITY || tn & VFP_ZERO)
1132 goto zero;
1133
1134 if (tn & VFP_DENORMAL)
1135 vfp_single_normalise_denormal(&vsn);
1136 if (tm & VFP_DENORMAL)
1137 vfp_single_normalise_denormal(&vsm);
1138
1139 /*
1140 * Ok, we have two numbers, we can perform division.
1141 */
1142 vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
1143 vsm.significand <<= 1;
1144 if (vsm.significand <= (2 * vsn.significand)) {
1145 vsn.significand >>= 1;
1146 vsd.exponent++;
1147 }
1148 {
1149 u64 significand = (u64)vsn.significand << 32;
1150 do_div(significand, vsm.significand);
1151 vsd.significand = significand;
1152 }
1153 if ((vsd.significand & 0x3f) == 0)
1154 vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
1155
1156 return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
1157
1158 vsn_nan:
1159 exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
1160 pack:
1161 vfp_put_float(state, vfp_single_pack(&vsd), sd);
1162 return exceptions;
1163
1164 vsm_nan:
1165 exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
1166 goto pack;
1167
1168 zero:
1169 vsd.exponent = 0;
1170 vsd.significand = 0;
1171 goto pack;
1172
1173 divzero:
1174 exceptions = FPSCR_DZC;
1175 infinity:
1176 vsd.exponent = 255;
1177 vsd.significand = 0;
1178 goto pack;
1179
1180 invalid:
1181 vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
1182 return FPSCR_IOC;
1183}
1184
1185static struct op fops[] = {
1186 { vfp_single_fmac, 0 },
1187 { vfp_single_fmsc, 0 },
1188 { vfp_single_fmul, 0 },
1189 { vfp_single_fadd, 0 },
1190 { vfp_single_fnmac, 0 },
1191 { vfp_single_fnmsc, 0 },
1192 { vfp_single_fnmul, 0 },
1193 { vfp_single_fsub, 0 },
1194 { vfp_single_fdiv, 0 },
1195};
1196
1197#define FREG_BANK(x) ((x) & 0x18)
1198#define FREG_IDX(x) ((x) & 7)
1199
1200u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
1201{
1202 u32 op = inst & FOP_MASK;
1203 u32 exceptions = 0;
1204 unsigned int dest;
1205 unsigned int sn = vfp_get_sn(inst);
1206 unsigned int sm = vfp_get_sm(inst);
1207 unsigned int vecitr, veclen, vecstride;
1208 struct op *fop;
1209 pr_debug("In %s\n", __FUNCTION__);
1210
1211 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
1212
1213 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1214
1215 /*
1216 * fcvtsd takes a dN register number as destination, not sN.
1217 * Technically, if bit 0 of dd is set, this is an invalid
1218 * instruction. However, we ignore this for efficiency.
1219 * It also only operates on scalars.
1220 */
1221 if (fop->flags & OP_DD)
1222 dest = vfp_get_dd(inst);
1223 else
1224 dest = vfp_get_sd(inst);
1225
1226 /*
1227 * If destination bank is zero, vector length is always '1'.
1228 * ARM DDI0100F C5.1.3, C5.3.2.
1229 */
1230 if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
1231 veclen = 0;
1232 else
1233 veclen = fpscr & FPSCR_LENGTH_MASK;
1234
1235 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1236 (veclen >> FPSCR_LENGTH_BIT) + 1);
1237
1238 if (!fop->fn) {
1239 printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]);
1240 exit(-1);
1241 goto invalid;
1242 }
1243
1244 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1245 s32 m = vfp_get_float(state, sm);
1246 u32 except;
1247 char type;
1248
1249 type = fop->flags & OP_DD ? 'd' : 's';
1250 if (op == FOP_EXT)
1251 pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
1252 vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
1253 sm, m);
1254 else
1255 pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
1256 vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
1257 FOP_TO_IDX(op), sm, m);
1258
1259 except = fop->fn(state, dest, sn, m, fpscr);
1260 pr_debug("VFP: itr%d: exceptions=%08x\n",
1261 vecitr >> FPSCR_LENGTH_BIT, except);
1262
1263 exceptions |= except;
1264
1265 /*
1266 * CHECK: It appears to be undefined whether we stop when
1267 * we encounter an exception. We continue.
1268 */
1269 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
1270 sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
1271 if (FREG_BANK(sm) != 0)
1272 sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
1273 }
1274 return exceptions;
1275
1276 invalid:
1277 return (u32)-1;
1278}
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{
99 MAX_REG_NUM, 99 MAX_REG_NUM,
100}; 100};
101 101
102#define VFP_OFFSET(x) (x - VFP_BASE) 102#define CP15(idx) (idx - CP15_BASE)
103#define VFP_OFFSET(x) (x - VFP_BASE)
104
103#endif 105#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 @@
20 20
21#ifndef __ARM_CPU_H__ 21#ifndef __ARM_CPU_H__
22#define __ARM_CPU_H__ 22#define __ARM_CPU_H__
23//#include <skyeye_thread.h>
24//#include <skyeye_obj.h>
25//#include <skyeye_mach.h>
26//#include <skyeye_exec.h>
27 23
28#include <stddef.h> 24#include <stddef.h>
29#include <stdio.h> 25#include <stdio.h>
30 26
31#include "common/thread.h" 27#include "common/thread.h"
32 28
29#include "core/arm/skyeye_common/armdefs.h"
33 30
34typedef struct ARM_CPU_State_s { 31typedef struct ARM_CPU_State_s {
35 ARMul_State * core; 32 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 @@
31 31
32#include "arm_regformat.h" 32#include "arm_regformat.h"
33#include "common/platform.h" 33#include "common/platform.h"
34#include "skyeye_defs.h" 34#include "core/arm/skyeye_common/skyeye_defs.h"
35 35
36//AJ2D-------------------------------------------------------------------------- 36//AJ2D--------------------------------------------------------------------------
37 37
@@ -130,7 +130,7 @@ typedef unsigned long long uint64_t;
130#endif 130#endif
131*/ 131*/
132 132
133#include "armmmu.h" 133#include "core/arm/skyeye_common/armmmu.h"
134//#include "lcd/skyeye_lcd.h" 134//#include "lcd/skyeye_lcd.h"
135 135
136 136
@@ -367,7 +367,6 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
367 367
368 int verbose; /* non-zero means print various messages like the banner */ 368 int verbose; /* non-zero means print various messages like the banner */
369 369
370 mmu_state_t mmu;
371 int mmu_inited; 370 int mmu_inited;
372 //mem_state_t mem; 371 //mem_state_t mem;
373 /*remove io_state to skyeye_mach_*.c files */ 372 /*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 @@
18#define __ARMEMU_H__ 18#define __ARMEMU_H__
19 19
20 20
21#include "armdefs.h" 21#include "core/arm/skyeye_common/armdefs.h"
22//#include "skyeye.h" 22//#include "skyeye.h"
23 23
24//extern ARMword isize; 24//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
134 134
135} fault_t; 135} fault_t;
136 136
137typedef struct mmu_ops_s
138{
139 /*initilization */
140 int (*init) (ARMul_State * state);
141 /*free on exit */
142 void (*exit) (ARMul_State * state);
143 /*read byte data */
144 fault_t (*read_byte) (ARMul_State * state, ARMword va,
145 ARMword * data);
146 /*write byte data */
147 fault_t (*write_byte) (ARMul_State * state, ARMword va,
148 ARMword data);
149 /*read halfword data */
150 fault_t (*read_halfword) (ARMul_State * state, ARMword va,
151 ARMword * data);
152 /*write halfword data */
153 fault_t (*write_halfword) (ARMul_State * state, ARMword va,
154 ARMword data);
155 /*read word data */
156 fault_t (*read_word) (ARMul_State * state, ARMword va,
157 ARMword * data);
158 /*write word data */
159 fault_t (*write_word) (ARMul_State * state, ARMword va,
160 ARMword data);
161 /*load instr */
162 fault_t (*load_instr) (ARMul_State * state, ARMword va,
163 ARMword * instr);
164 /*mcr */
165 ARMword (*mcr) (ARMul_State * state, ARMword instr, ARMword val);
166 /*mrc */
167 ARMword (*mrc) (ARMul_State * state, ARMword instr, ARMword * val);
168
169 /*ywc 2005-04-16 convert virtual address to physics address */
170 int (*v2p_dbct) (ARMul_State * state, ARMword virt_addr,
171 ARMword * phys_addr);
172} mmu_ops_t;
173
174
175#include "core/arm/interpreter/mmu/tlb.h"
176#include "core/arm/interpreter/mmu/rb.h"
177#include "core/arm/interpreter/mmu/wb.h"
178#include "core/arm/interpreter/mmu/cache.h"
179
180/*special process mmu.h*/
181#include "core/arm/interpreter/mmu/sa_mmu.h"
182//#include "core/arm/interpreter/mmu/arm7100_mmu.h"
183//#include "core/arm/interpreter/mmu/arm920t_mmu.h"
184//#include "core/arm/interpreter/mmu/arm926ejs_mmu.h"
185#include "core/arm/interpreter/mmu/arm1176jzf_s_mmu.h"
186//#include "core/arm/interpreter/mmu/cortex_a9_mmu.h"
187
188typedef struct mmu_state_t
189{
190 ARMword control;
191 ARMword translation_table_base;
192/* dyf 201-08-11 for arm1176 */
193 ARMword auxiliary_control;
194 ARMword coprocessor_access_control;
195 ARMword translation_table_base0;
196 ARMword translation_table_base1;
197 ARMword translation_table_ctrl;
198/* arm1176 end */
199
200 ARMword domain_access_control;
201 ARMword fault_status;
202 ARMword fault_statusi; /* prefetch fault status */
203 ARMword fault_address;
204 ARMword last_domain;
205 ARMword process_id;
206 ARMword context_id;
207 ARMword thread_uro_id;
208 ARMword cache_locked_down;
209 ARMword tlb_locked_down;
210//chy 2003-08-24 for xscale
211 ARMword cache_type; // 0
212 ARMword aux_control; // 1
213 ARMword copro_access; // 15
214
215 mmu_ops_t ops;
216 union
217 {
218 sa_mmu_t sa_mmu;
219 //arm7100_mmu_t arm7100_mmu;
220 //arm920t_mmu_t arm920t_mmu;
221 //arm926ejs_mmu_t arm926ejs_mmu;
222 } u;
223} mmu_state_t;
224
225int mmu_init (ARMul_State * state);
226int mmu_reset (ARMul_State * state);
227void mmu_exit (ARMul_State * state);
228
229fault_t mmu_read_word (ARMul_State * state, ARMword virt_addr,
230 ARMword * data);
231fault_t mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data);
232fault_t mmu_load_instr (ARMul_State * state, ARMword virt_addr,
233 ARMword * instr);
234
235ARMword mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value);
236void mmu_mcr (ARMul_State * state, ARMword instr, ARMword value);
237
238/*ywc 20050416*/
239int mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr,
240 ARMword * phys_addr);
241
242fault_t
243mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data);
244fault_t
245mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data);
246fault_t
247mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data);
248fault_t
249mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data);
250fault_t
251mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data);
252fault_t
253mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data);
254#endif /* _ARMMMU_H_ */ 137#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 @@
15 along with this program; if not, write to the Free Software 15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17 17
18//#include "bank_defs.h" 18#include <stdint.h>
19//#include "dyncom/defines.h"
20
21//typedef struct mmap_area{
22// mem_bank_t bank;
23// void *mmap_addr;
24// struct mmap_area *next;
25//}mmap_area_t;
26 19
27#if FAST_MEMORY 20#if FAST_MEMORY
28/* in user mode, mmap_base will be on initial brk, 21/* 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
108 align_t alignment; 108 align_t alignment;
109} generic_arch_t; 109} generic_arch_t;
110 110
111#endif \ No newline at end of file 111typedef u32 addr_t;
112
113#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 @@
1/*
2 skyeye_types.h - some data types definition for skyeye debugger
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.sf.linuxforum.net>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20*/
21/*
22 * 12/16/2006 Michael.Kang <blackfin.kang@gmail.com>
23 */
24
25#ifndef __SKYEYE_TYPES_H
26#define __SKYEYE_TYPES_H
27
28#include <stdint.h>
29
30/*default machine word length */
31
32#ifndef __BEOS__
33/* To avoid the type conflict with the qemu */
34#ifndef QEMU
35typedef uint8_t uint8;
36typedef uint16_t uint16;
37typedef uint32_t uint32;
38typedef uint64_t uint64;
39
40typedef int8_t sint8;
41typedef int16_t sint16;
42typedef int32_t sint32;
43typedef int64_t sint64;
44#endif
45
46typedef uint32_t address_t;
47typedef uint32_t uinteger_t;
48typedef int32_t integer_t;
49
50typedef uint32_t physical_address_t;
51typedef uint32_t generic_address_t;
52
53#endif
54
55#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 @@
1/*
2 armvfp.c - ARM VFPv3 emulation unit
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/* Note: this file handles interface with arm core and vfp registers */
22
23/* Opens debug for classic interpreter only */
24//#define DEBUG
25
26#include "common/common.h"
27
28#include "core/arm/skyeye_common/armdefs.h"
29#include "core/arm/skyeye_common/vfp/vfp.h"
30
31#define DEBUG DBG
32
33//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
34
35unsigned
36VFPInit (ARMul_State *state)
37{
38 state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
39 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
40 state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
41 state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
42
43 //persistent_state = state;
44 /* Reset only specify VFP_FPEXC_EN = '0' */
45
46 return 0;
47}
48
49unsigned
50VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
51{
52 /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
53 int CoProc = BITS (8, 11); /* 10 or 11 */
54 int OPC_1 = BITS (21, 23);
55 int Rt = BITS (12, 15);
56 int CRn = BITS (16, 19);
57 int CRm = BITS (0, 3);
58 int OPC_2 = BITS (5, 7);
59
60 /* TODO check access permission */
61
62 /* CRn/opc1 CRm/opc2 */
63
64 if (CoProc == 10 || CoProc == 11) {
65#define VFP_MRC_TRANS
66#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
67#undef VFP_MRC_TRANS
68 }
69 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
70 instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
71
72 return ARMul_CANT;
73}
74
75unsigned
76VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value)
77{
78 /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
79 int CoProc = BITS (8, 11); /* 10 or 11 */
80 int OPC_1 = BITS (21, 23);
81 int Rt = BITS (12, 15);
82 int CRn = BITS (16, 19);
83 int CRm = BITS (0, 3);
84 int OPC_2 = BITS (5, 7);
85
86 /* TODO check access permission */
87
88 /* CRn/opc1 CRm/opc2 */
89 if (CoProc == 10 || CoProc == 11) {
90#define VFP_MCR_TRANS
91#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
92#undef VFP_MCR_TRANS
93 }
94 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
95 instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
96
97 return ARMul_CANT;
98}
99
100unsigned
101VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2)
102{
103 /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
104 int CoProc = BITS (8, 11); /* 10 or 11 */
105 int OPC_1 = BITS (4, 7);
106 int Rt = BITS (12, 15);
107 int Rt2 = BITS (16, 19);
108 int CRm = BITS (0, 3);
109
110 if (CoProc == 10 || CoProc == 11) {
111#define VFP_MRRC_TRANS
112#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
113#undef VFP_MRRC_TRANS
114 }
115 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
116 instr, CoProc, OPC_1, Rt, Rt2, CRm);
117
118 return ARMul_CANT;
119}
120
121unsigned
122VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2)
123{
124 /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
125 int CoProc = BITS (8, 11); /* 10 or 11 */
126 int OPC_1 = BITS (4, 7);
127 int Rt = BITS (12, 15);
128 int Rt2 = BITS (16, 19);
129 int CRm = BITS (0, 3);
130
131 /* TODO check access permission */
132
133 /* CRn/opc1 CRm/opc2 */
134
135 if (CoProc == 11 || CoProc == 10) {
136#define VFP_MCRR_TRANS
137#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
138#undef VFP_MCRR_TRANS
139 }
140 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
141 instr, CoProc, OPC_1, Rt, Rt2, CRm);
142
143 return ARMul_CANT;
144}
145
146unsigned
147VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
148{
149 /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
150 int CoProc = BITS (8, 11); /* 10 or 11 */
151 int CRd = BITS (12, 15);
152 int Rn = BITS (16, 19);
153 int imm8 = BITS (0, 7);
154 int P = BIT(24);
155 int U = BIT(23);
156 int D = BIT(22);
157 int W = BIT(21);
158
159 /* TODO check access permission */
160
161 /* VSTM */
162 if ( (P|U|D|W) == 0 ) {
163 DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
164 exit(-1);
165 }
166 if (CoProc == 10 || CoProc == 11) {
167#if 1
168 if (P == 0 && U == 0 && W == 0) {
169 DEBUG("VSTM Related encodings\n");
170 exit(-1);
171 }
172 if (P == U && W == 1) {
173 DEBUG("UNDEFINED\n");
174 exit(-1);
175 }
176#endif
177
178#define VFP_STC_TRANS
179#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
180#undef VFP_STC_TRANS
181 }
182 DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
183 instr, CoProc, CRd, Rn, imm8, P, U, D, W);
184
185 return ARMul_CANT;
186}
187
188unsigned
189VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value)
190{
191 /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
192 int CoProc = BITS (8, 11); /* 10 or 11 */
193 int CRd = BITS (12, 15);
194 int Rn = BITS (16, 19);
195 int imm8 = BITS (0, 7);
196 int P = BIT(24);
197 int U = BIT(23);
198 int D = BIT(22);
199 int W = BIT(21);
200
201 /* TODO check access permission */
202
203 if ( (P|U|D|W) == 0 ) {
204 DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
205 exit(-1);
206 }
207 if (CoProc == 10 || CoProc == 11) {
208#define VFP_LDC_TRANS
209#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
210#undef VFP_LDC_TRANS
211 }
212 DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
213 instr, CoProc, CRd, Rn, imm8, P, U, D, W);
214
215 return ARMul_CANT;
216}
217
218unsigned
219VFPCDP (ARMul_State * state, unsigned type, u32 instr)
220{
221 /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
222 int CoProc = BITS (8, 11); /* 10 or 11 */
223 int OPC_1 = BITS (20, 23);
224 int CRd = BITS (12, 15);
225 int CRn = BITS (16, 19);
226 int CRm = BITS (0, 3);
227 int OPC_2 = BITS (5, 7);
228
229 //ichfly
230 /*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)
231 {
232 struct vfp_double vdd;
233 struct vfp_single vsd;
234 int dn = BITS(12, 15) + (BIT(22) << 4);
235 int sd = (BITS(0, 3) << 1) + BIT(5);
236 s32 n = vfp_get_float(state, sd);
237 vfp_single_unpack(&vsd, n);
238 if (vsd.exponent & 0x80)
239 {
240 vdd.exponent = (vsd.exponent&~0x80) | 0x400;
241 }
242 else
243 {
244 vdd.exponent = vsd.exponent | 0x380;
245 }
246 vdd.sign = vsd.sign;
247 vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand
248 vfp_put_double(state, vfp_double_pack(&vdd), dn);
249 return ARMul_DONE;
250 }
251 if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6
252 {
253 struct vfp_double vdd;
254 struct vfp_single vsd;
255 int sd = BITS(0, 3) + (BIT(5) << 4);
256 int dn = (BITS(12, 15) << 1) + BIT(22);
257 vfp_double_unpack(&vdd, vfp_get_double(state, sd));
258 if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert
259 {
260 vsd.exponent = (vdd.exponent) | 0x80;
261 }
262 else
263 {
264 vsd.exponent = vdd.exponent & ~0x80;
265 }
266 vsd.exponent &= 0xFF;
267 // vsd.exponent = vdd.exponent >> 3;
268 vsd.sign = vdd.sign;
269 vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000;
270 vfp_put_float(state, vfp_single_pack(&vsd), dn);
271 return ARMul_DONE;
272 }*/
273
274 /* TODO check access permission */
275
276 /* CRn/opc1 CRm/opc2 */
277
278 if (CoProc == 10 || CoProc == 11) {
279#define VFP_CDP_TRANS
280#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
281#undef VFP_CDP_TRANS
282
283 int exceptions = 0;
284 if (CoProc == 10)
285 exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
286 else
287 exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
288
289 vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
290
291 return ARMul_DONE;
292 }
293 DEBUG("Can't identify %x\n", instr);
294 return ARMul_CANT;
295}
296
297
298/* ----------- MRC ------------ */
299#define VFP_MRC_IMPL
300#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
301#undef VFP_MRC_IMPL
302
303#define VFP_MRRC_IMPL
304#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
305#undef VFP_MRRC_IMPL
306
307
308/* ----------- MCR ------------ */
309#define VFP_MCR_IMPL
310#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
311#undef VFP_MCR_IMPL
312
313#define VFP_MCRR_IMPL
314#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
315#undef VFP_MCRR_IMPL
316
317/* Memory operation are not inlined, as old Interpreter and Fast interpreter
318 don't have the same memory operation interface.
319 Old interpreter framework does one access to coprocessor per data, and
320 handles already data write, as well as address computation,
321 which is not the case for Fast interpreter. Therefore, implementation
322 of vfp instructions in old interpreter and fast interpreter are separate. */
323
324/* ----------- STC ------------ */
325#define VFP_STC_IMPL
326#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
327#undef VFP_STC_IMPL
328
329
330/* ----------- LDC ------------ */
331#define VFP_LDC_IMPL
332#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
333#undef VFP_LDC_IMPL
334
335
336/* ----------- CDP ------------ */
337#define VFP_CDP_IMPL
338#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
339#undef VFP_CDP_IMPL
340
341/* Miscellaneous functions */
342int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
343{
344 DEBUG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
345 return state->ExtReg[reg];
346}
347
348void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg)
349{
350 DEBUG("VFP put float: s%d <= [%08x]\n", reg, val);
351 state->ExtReg[reg] = val;
352}
353
354uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
355{
356 uint64_t result;
357 result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
358 DEBUG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
359 return result;
360}
361
362void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
363{
364 DEBUG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
365 state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
366 state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
367}
368
369
370
371/*
372 * Process bitmask of exception conditions. (from vfpmodule.c)
373 */
374void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
375{
376 int si_code = 0;
377
378 vfpdebug("VFP: raising exceptions %08x\n", exceptions);
379
380 if (exceptions == VFP_EXCEPTION_ERROR) {
381 DEBUG("unhandled bounce %x\n", inst);
382 exit(-1);
383 return;
384 }
385
386 /*
387 * If any of the status flags are set, update the FPSCR.
388 * Comparison instructions always return at least one of
389 * these flags set.
390 */
391 if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
392 fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
393
394 fpscr |= exceptions;
395
396 state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
397}
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 @@
25 25
26#define vfpdebug //printf 26#define vfpdebug //printf
27 27
28#include "core/arm/interpreter/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ 28#include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
29 29
30unsigned VFPInit (ARMul_State *state); 30unsigned VFPInit (ARMul_State *state);
31unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value); 31unsigned 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);
88u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); 88u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
89 89
90/* MRC */ 90/* MRC */
91inline void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); 91void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value);
92inline void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); 92void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value);
93inline void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); 93void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2);
94inline void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); 94void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
95inline void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); 95void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
96/* MCR */ 96/* MCR */
97inline void VMSR(ARMul_State * state, ARMword reg, ARMword Rt); 97void VMSR(ARMul_State * state, ARMword reg, ARMword Rt);
98/* STC */ 98/* STC */
99inline int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value); 99int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value);
100inline int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value); 100int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value);
101inline int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value); 101int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value);
102/* LDC */ 102/* LDC */
103inline int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value); 103int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value);
104inline int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value); 104int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value);
105inline int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value); 105int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value);
106 106
107#ifdef __cplusplus 107#ifdef __cplusplus
108 } 108 }
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 @@
38#include <stdint.h> 38#include <stdint.h>
39#include <stdio.h> 39#include <stdio.h>
40 40
41#include "core/arm/interpreter/armdefs.h" 41#include "common/common_types.h"
42 42#include "core/arm/skyeye_common/armdefs.h"
43#define u16 uint16_t
44#define u32 uint32_t
45#define u64 uint64_t
46#define s16 int16_t
47#define s32 int32_t
48#define s64 int64_t
49 43
50#define pr_info //printf 44#define pr_info //printf
51#define pr_debug //printf 45#define pr_debug //printf
52 46
53static u32 vfp_fls(int x); 47static u32 fls(ARMword x);
54#define do_div(n, base) {n/=base;} 48#define do_div(n, base) {n/=base;}
55 49
56/* From vfpinstr.h */ 50/* From vfpinstr.h */
@@ -508,7 +502,7 @@ struct op {
508 u32 flags; 502 u32 flags;
509}; 503};
510 504
511static u32 vfp_fls(int x) 505static u32 fls(ARMword x)
512{ 506{
513 int r = 32; 507 int r = 32;
514 508
@@ -538,4 +532,9 @@ static u32 vfp_fls(int x)
538 532
539} 533}
540 534
535u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func);
536u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr);
537u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr);
538u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr);
539
541#endif 540#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 @@
1/*
2 vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * This code is derived in part from :
23 * - Android kernel
24 * - John R. Housers softfloat library, which
25 * carries the following notice:
26 *
27 * ===========================================================================
28 * This C source file is part of the SoftFloat IEC/IEEE Floating-point
29 * Arithmetic Package, Release 2.
30 *
31 * Written by John R. Hauser. This work was made possible in part by the
32 * International Computer Science Institute, located at Suite 600, 1947 Center
33 * Street, Berkeley, California 94704. Funding was partially provided by the
34 * National Science Foundation under grant MIP-9311980. The original version
35 * of this code was written as part of a project to build a fixed-point vector
36 * processor in collaboration with the University of California at Berkeley,
37 * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
38 * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
39 * arithmetic/softfloat.html'.
40 *
41 * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
42 * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
43 * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
44 * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
45 * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
46 *
47 * Derivative works are acceptable, even for commercial purposes, so long as
48 * (1) they include prominent notice that the work is derivative, and (2) they
49 * include prominent notice akin to these three paragraphs for those parts of
50 * this code that are retained.
51 * ===========================================================================
52 */
53
54#include "core/arm/skyeye_common/vfp/vfp.h"
55#include "core/arm/skyeye_common/vfp/vfp_helper.h"
56#include "core/arm/skyeye_common/vfp/asm_vfp.h"
57
58static struct vfp_double vfp_double_default_qnan = {
59 2047,
60 0,
61 VFP_DOUBLE_SIGNIFICAND_QNAN,
62};
63
64static void vfp_double_dump(const char *str, struct vfp_double *d)
65{
66 pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
67 str, d->sign != 0, d->exponent, d->significand);
68}
69
70static void vfp_double_normalise_denormal(struct vfp_double *vd)
71{
72 int bits = 31 - fls((ARMword)(vd->significand >> 32));
73 if (bits == 31)
74 bits = 63 - fls((ARMword)vd->significand);
75
76 vfp_double_dump("normalise_denormal: in", vd);
77
78 if (bits) {
79 vd->exponent -= bits - 1;
80 vd->significand <<= bits;
81 }
82
83 vfp_double_dump("normalise_denormal: out", vd);
84}
85
86u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
87{
88 u64 significand, incr;
89 int exponent, shift, underflow;
90 u32 rmode;
91
92 vfp_double_dump("pack: in", vd);
93
94 /*
95 * Infinities and NaNs are a special case.
96 */
97 if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
98 goto pack;
99
100 /*
101 * Special-case zero.
102 */
103 if (vd->significand == 0) {
104 vd->exponent = 0;
105 goto pack;
106 }
107
108 exponent = vd->exponent;
109 significand = vd->significand;
110
111 shift = 32 - fls((ARMword)(significand >> 32));
112 if (shift == 32)
113 shift = 64 - fls((ARMword)significand);
114 if (shift) {
115 exponent -= shift;
116 significand <<= shift;
117 }
118
119#if 1
120 vd->exponent = exponent;
121 vd->significand = significand;
122 vfp_double_dump("pack: normalised", vd);
123#endif
124
125 /*
126 * Tiny number?
127 */
128 underflow = exponent < 0;
129 if (underflow) {
130 significand = vfp_shiftright64jamming(significand, -exponent);
131 exponent = 0;
132#if 1
133 vd->exponent = exponent;
134 vd->significand = significand;
135 vfp_double_dump("pack: tiny number", vd);
136#endif
137 if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
138 underflow = 0;
139 }
140
141 /*
142 * Select rounding increment.
143 */
144 incr = 0;
145 rmode = fpscr & FPSCR_RMODE_MASK;
146
147 if (rmode == FPSCR_ROUND_NEAREST) {
148 incr = 1ULL << VFP_DOUBLE_LOW_BITS;
149 if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
150 incr -= 1;
151 }
152 else if (rmode == FPSCR_ROUND_TOZERO) {
153 incr = 0;
154 }
155 else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
156 incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
157
158 pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
159
160 /*
161 * Is our rounding going to overflow?
162 */
163 if ((significand + incr) < significand) {
164 exponent += 1;
165 significand = (significand >> 1) | (significand & 1);
166 incr >>= 1;
167#if 1
168 vd->exponent = exponent;
169 vd->significand = significand;
170 vfp_double_dump("pack: overflow", vd);
171#endif
172 }
173
174 /*
175 * If any of the low bits (which will be shifted out of the
176 * number) are non-zero, the result is inexact.
177 */
178 if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
179 exceptions |= FPSCR_IXC;
180
181 /*
182 * Do our rounding.
183 */
184 significand += incr;
185
186 /*
187 * Infinity?
188 */
189 if (exponent >= 2046) {
190 exceptions |= FPSCR_OFC | FPSCR_IXC;
191 if (incr == 0) {
192 vd->exponent = 2045;
193 vd->significand = 0x7fffffffffffffffULL;
194 }
195 else {
196 vd->exponent = 2047; /* infinity */
197 vd->significand = 0;
198 }
199 }
200 else {
201 if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
202 exponent = 0;
203 if (exponent || significand > 0x8000000000000000ULL)
204 underflow = 0;
205 if (underflow)
206 exceptions |= FPSCR_UFC;
207 vd->exponent = exponent;
208 vd->significand = significand >> 1;
209 }
210 pack:
211 return 0;
212}
213
214u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
215{
216 u64 significand, incr;
217 int exponent, shift, underflow;
218 u32 rmode;
219
220 vfp_double_dump("pack: in", vd);
221
222 /*
223 * Infinities and NaNs are a special case.
224 */
225 if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
226 goto pack;
227
228 /*
229 * Special-case zero.
230 */
231 if (vd->significand == 0) {
232 vd->exponent = 0;
233 goto pack;
234 }
235
236 exponent = vd->exponent;
237 significand = vd->significand;
238
239 shift = 32 - fls((ARMword)(significand >> 32));
240 if (shift == 32)
241 shift = 64 - fls((ARMword)significand);
242 if (shift) {
243 exponent -= shift;
244 significand <<= shift;
245 }
246
247#if 1
248 vd->exponent = exponent;
249 vd->significand = significand;
250 vfp_double_dump("pack: normalised", vd);
251#endif
252
253 /*
254 * Tiny number?
255 */
256 underflow = exponent < 0;
257 if (underflow) {
258 significand = vfp_shiftright64jamming(significand, -exponent);
259 exponent = 0;
260#if 1
261 vd->exponent = exponent;
262 vd->significand = significand;
263 vfp_double_dump("pack: tiny number", vd);
264#endif
265 if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
266 underflow = 0;
267 }
268
269 /*
270 * Select rounding increment.
271 */
272 incr = 0;
273 rmode = fpscr & FPSCR_RMODE_MASK;
274
275 if (rmode == FPSCR_ROUND_NEAREST) {
276 incr = 1ULL << VFP_DOUBLE_LOW_BITS;
277 if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
278 incr -= 1;
279 } else if (rmode == FPSCR_ROUND_TOZERO) {
280 incr = 0;
281 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
282 incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
283
284 pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
285
286 /*
287 * Is our rounding going to overflow?
288 */
289 if ((significand + incr) < significand) {
290 exponent += 1;
291 significand = (significand >> 1) | (significand & 1);
292 incr >>= 1;
293#if 1
294 vd->exponent = exponent;
295 vd->significand = significand;
296 vfp_double_dump("pack: overflow", vd);
297#endif
298 }
299
300 /*
301 * If any of the low bits (which will be shifted out of the
302 * number) are non-zero, the result is inexact.
303 */
304 if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
305 exceptions |= FPSCR_IXC;
306
307 /*
308 * Do our rounding.
309 */
310 significand += incr;
311
312 /*
313 * Infinity?
314 */
315 if (exponent >= 2046) {
316 exceptions |= FPSCR_OFC | FPSCR_IXC;
317 if (incr == 0) {
318 vd->exponent = 2045;
319 vd->significand = 0x7fffffffffffffffULL;
320 } else {
321 vd->exponent = 2047; /* infinity */
322 vd->significand = 0;
323 }
324 } else {
325 if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
326 exponent = 0;
327 if (exponent || significand > 0x8000000000000000ULL)
328 underflow = 0;
329 if (underflow)
330 exceptions |= FPSCR_UFC;
331 vd->exponent = exponent;
332 vd->significand = significand >> 1;
333 }
334
335pack:
336 vfp_double_dump("pack: final", vd);
337 {
338 s64 d = vfp_double_pack(vd);
339 pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func,
340 dd, d, exceptions);
341 vfp_put_double(state, d, dd);
342 }
343 return exceptions;
344}
345
346/*
347 * Propagate the NaN, setting exceptions if it is signalling.
348 * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
349 */
350static u32
351vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
352 struct vfp_double *vdm, u32 fpscr)
353{
354 struct vfp_double *nan;
355 int tn, tm = 0;
356
357 tn = vfp_double_type(vdn);
358
359 if (vdm)
360 tm = vfp_double_type(vdm);
361
362 if (fpscr & FPSCR_DEFAULT_NAN)
363 /*
364 * Default NaN mode - always returns a quiet NaN
365 */
366 nan = &vfp_double_default_qnan;
367 else {
368 /*
369 * Contemporary mode - select the first signalling
370 * NAN, or if neither are signalling, the first
371 * quiet NAN.
372 */
373 if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
374 nan = vdn;
375 else
376 nan = vdm;
377 /*
378 * Make the NaN quiet.
379 */
380 nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
381 }
382
383 *vdd = *nan;
384
385 /*
386 * If one was a signalling NAN, raise invalid operation.
387 */
388 return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
389}
390
391/*
392 * Extended operations
393 */
394static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
395{
396 pr_debug("In %s\n", __FUNCTION__);
397 vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd);
398 return 0;
399}
400
401static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
402{
403 pr_debug("In %s\n", __FUNCTION__);
404 vfp_put_double(state, vfp_get_double(state, dm), dd);
405 return 0;
406}
407
408static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
409{
410 pr_debug("In %s\n", __FUNCTION__);
411 vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd);
412 return 0;
413}
414
415static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
416{
417 pr_debug("In %s\n", __FUNCTION__);
418 vfp_double vdm, vdd, *vdp;
419 int ret, tm;
420
421 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
422 tm = vfp_double_type(&vdm);
423 if (tm & (VFP_NAN|VFP_INFINITY)) {
424 vdp = &vdd;
425
426 if (tm & VFP_NAN)
427 ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
428 else if (vdm.sign == 0) {
429sqrt_copy:
430 vdp = &vdm;
431 ret = 0;
432 } else {
433sqrt_invalid:
434 vdp = &vfp_double_default_qnan;
435 ret = FPSCR_IOC;
436 }
437 vfp_put_double(state, vfp_double_pack(vdp), dd);
438 return ret;
439 }
440
441 /*
442 * sqrt(+/- 0) == +/- 0
443 */
444 if (tm & VFP_ZERO)
445 goto sqrt_copy;
446
447 /*
448 * Normalise a denormalised number
449 */
450 if (tm & VFP_DENORMAL)
451 vfp_double_normalise_denormal(&vdm);
452
453 /*
454 * sqrt(<0) = invalid
455 */
456 if (vdm.sign)
457 goto sqrt_invalid;
458
459 vfp_double_dump("sqrt", &vdm);
460
461 /*
462 * Estimate the square root.
463 */
464 vdd.sign = 0;
465 vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
466 vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
467
468 vfp_double_dump("sqrt estimate1", &vdd);
469
470 vdm.significand >>= 1 + (vdm.exponent & 1);
471 vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
472
473 vfp_double_dump("sqrt estimate2", &vdd);
474
475 /*
476 * And now adjust.
477 */
478 if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
479 if (vdd.significand < 2) {
480 vdd.significand = ~0ULL;
481 } else {
482 u64 termh, terml, remh, reml;
483 vdm.significand <<= 2;
484 mul64to128(&termh, &terml, vdd.significand, vdd.significand);
485 sub128(&remh, &reml, vdm.significand, 0, termh, terml);
486 while ((s64)remh < 0) {
487 vdd.significand -= 1;
488 shift64left(&termh, &terml, vdd.significand);
489 terml |= 1;
490 add128(&remh, &reml, remh, reml, termh, terml);
491 }
492 vdd.significand |= (remh | reml) != 0;
493 }
494 }
495 vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
496
497 return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt");
498}
499
500/*
501 * Equal := ZC
502 * Less than := N
503 * Greater than := C
504 * Unordered := CV
505 */
506static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr)
507{
508 s64 d, m;
509 u32 ret = 0;
510
511 pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr);
512 m = vfp_get_double(state, dm);
513 if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
514 ret |= FPSCR_C | FPSCR_V;
515 if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
516 /*
517 * Signalling NaN, or signalling on quiet NaN
518 */
519 ret |= FPSCR_IOC;
520 }
521
522 d = vfp_get_double(state, dd);
523 if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
524 ret |= FPSCR_C | FPSCR_V;
525 if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
526 /*
527 * Signalling NaN, or signalling on quiet NaN
528 */
529 ret |= FPSCR_IOC;
530 }
531
532 if (ret == 0) {
533 //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
534 if (d == m || vfp_double_packed_abs(d | m) == 0) {
535 /*
536 * equal
537 */
538 ret |= FPSCR_Z | FPSCR_C;
539 //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
540 } else if (vfp_double_packed_sign(d ^ m)) {
541 /*
542 * different signs
543 */
544 if (vfp_double_packed_sign(d))
545 /*
546 * d is negative, so d < m
547 */
548 ret |= FPSCR_N;
549 else
550 /*
551 * d is positive, so d > m
552 */
553 ret |= FPSCR_C;
554 } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
555 /*
556 * d < m
557 */
558 ret |= FPSCR_N;
559 } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
560 /*
561 * d > m
562 */
563 ret |= FPSCR_C;
564 }
565 }
566 pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret);
567
568 return ret;
569}
570
571static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
572{
573 pr_debug("In %s\n", __FUNCTION__);
574 return vfp_compare(state, dd, 0, dm, fpscr);
575}
576
577static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
578{
579 pr_debug("In %s\n", __FUNCTION__);
580 return vfp_compare(state, dd, 1, dm, fpscr);
581}
582
583static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
584{
585 pr_debug("In %s\n", __FUNCTION__);
586 return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr);
587}
588
589static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
590{
591 pr_debug("In %s\n", __FUNCTION__);
592 return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
593}
594
595u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr) //ichfly for internal use only
596{
597 struct vfp_single vsd;
598 int tm;
599 u32 exceptions = 0;
600
601 pr_debug("In %s\n", __FUNCTION__);
602
603 tm = vfp_double_type(dm);
604
605 /*
606 * If we have a signalling NaN, signal invalid operation.
607 */
608 if (tm == VFP_SNAN)
609 exceptions = FPSCR_IOC;
610
611 if (tm & VFP_DENORMAL)
612 vfp_double_normalise_denormal(dm);
613
614 vsd.sign = dm->sign;
615 vsd.significand = vfp_hi64to32jamming(dm->significand);
616
617 /*
618 * If we have an infinity or a NaN, the exponent must be 255
619 */
620 if (tm & (VFP_INFINITY | VFP_NAN)) {
621 vsd.exponent = 255;
622 if (tm == VFP_QNAN)
623 vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
624 goto pack_nan;
625 }
626 else if (tm & VFP_ZERO)
627 vsd.exponent = 0;
628 else
629 vsd.exponent = dm->exponent - (1023 - 127);
630
631 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
632
633pack_nan:
634 vfp_put_float(state, vfp_single_pack(&vsd), sd);
635 return exceptions;
636}
637
638static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
639{
640 struct vfp_double vdm;
641 struct vfp_single vsd;
642 int tm;
643 u32 exceptions = 0;
644
645 pr_debug("In %s\n", __FUNCTION__);
646 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
647
648 tm = vfp_double_type(&vdm);
649
650 /*
651 * If we have a signalling NaN, signal invalid operation.
652 */
653 if (tm == VFP_SNAN)
654 exceptions = FPSCR_IOC;
655
656 if (tm & VFP_DENORMAL)
657 vfp_double_normalise_denormal(&vdm);
658
659 vsd.sign = vdm.sign;
660 vsd.significand = vfp_hi64to32jamming(vdm.significand);
661
662 /*
663 * If we have an infinity or a NaN, the exponent must be 255
664 */
665 if (tm & (VFP_INFINITY|VFP_NAN)) {
666 vsd.exponent = 255;
667 if (tm == VFP_QNAN)
668 vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
669 goto pack_nan;
670 } else if (tm & VFP_ZERO)
671 vsd.exponent = 0;
672 else
673 vsd.exponent = vdm.exponent - (1023 - 127);
674
675 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
676
677pack_nan:
678 vfp_put_float(state, vfp_single_pack(&vsd), sd);
679 return exceptions;
680}
681
682static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
683{
684 struct vfp_double vdm;
685 u32 m = vfp_get_float(state, dm);
686
687 pr_debug("In %s\n", __FUNCTION__);
688 vdm.sign = 0;
689 vdm.exponent = 1023 + 63 - 1;
690 vdm.significand = (u64)m;
691
692 return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito");
693}
694
695static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
696{
697 struct vfp_double vdm;
698 u32 m = vfp_get_float(state, dm);
699
700 pr_debug("In %s\n", __FUNCTION__);
701 vdm.sign = (m & 0x80000000) >> 16;
702 vdm.exponent = 1023 + 63 - 1;
703 vdm.significand = vdm.sign ? -m : m;
704
705 return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito");
706}
707
708static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
709{
710 struct vfp_double vdm;
711 u32 d, exceptions = 0;
712 int rmode = fpscr & FPSCR_RMODE_MASK;
713 int tm;
714
715 pr_debug("In %s\n", __FUNCTION__);
716 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
717
718 /*
719 * Do we have a denormalised number?
720 */
721 tm = vfp_double_type(&vdm);
722 if (tm & VFP_DENORMAL)
723 exceptions |= FPSCR_IDC;
724
725 if (tm & VFP_NAN)
726 vdm.sign = 0;
727
728 if (vdm.exponent >= 1023 + 32) {
729 d = vdm.sign ? 0 : 0xffffffff;
730 exceptions = FPSCR_IOC;
731 } else if (vdm.exponent >= 1023 - 1) {
732 int shift = 1023 + 63 - vdm.exponent;
733 u64 rem, incr = 0;
734
735 /*
736 * 2^0 <= m < 2^32-2^8
737 */
738 d = (ARMword)((vdm.significand << 1) >> shift);
739 rem = vdm.significand << (65 - shift);
740
741 if (rmode == FPSCR_ROUND_NEAREST) {
742 incr = 0x8000000000000000ULL;
743 if ((d & 1) == 0)
744 incr -= 1;
745 } else if (rmode == FPSCR_ROUND_TOZERO) {
746 incr = 0;
747 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
748 incr = ~0ULL;
749 }
750
751 if ((rem + incr) < rem) {
752 if (d < 0xffffffff)
753 d += 1;
754 else
755 exceptions |= FPSCR_IOC;
756 }
757
758 if (d && vdm.sign) {
759 d = 0;
760 exceptions |= FPSCR_IOC;
761 } else if (rem)
762 exceptions |= FPSCR_IXC;
763 } else {
764 d = 0;
765 if (vdm.exponent | vdm.significand) {
766 exceptions |= FPSCR_IXC;
767 if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
768 d = 1;
769 else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
770 d = 0;
771 exceptions |= FPSCR_IOC;
772 }
773 }
774 }
775
776 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
777
778 vfp_put_float(state, d, sd);
779
780 return exceptions;
781}
782
783static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
784{
785 pr_debug("In %s\n", __FUNCTION__);
786 return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO);
787}
788
789static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
790{
791 struct vfp_double vdm;
792 u32 d, exceptions = 0;
793 int rmode = fpscr & FPSCR_RMODE_MASK;
794 int tm;
795
796 pr_debug("In %s\n", __FUNCTION__);
797 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
798 vfp_double_dump("VDM", &vdm);
799
800 /*
801 * Do we have denormalised number?
802 */
803 tm = vfp_double_type(&vdm);
804 if (tm & VFP_DENORMAL)
805 exceptions |= FPSCR_IDC;
806
807 if (tm & VFP_NAN) {
808 d = 0;
809 exceptions |= FPSCR_IOC;
810 } else if (vdm.exponent >= 1023 + 32) {
811 d = 0x7fffffff;
812 if (vdm.sign)
813 d = ~d;
814 exceptions |= FPSCR_IOC;
815 } else if (vdm.exponent >= 1023 - 1) {
816 int shift = 1023 + 63 - vdm.exponent; /* 58 */
817 u64 rem, incr = 0;
818
819 d = (ARMword)((vdm.significand << 1) >> shift);
820 rem = vdm.significand << (65 - shift);
821
822 if (rmode == FPSCR_ROUND_NEAREST) {
823 incr = 0x8000000000000000ULL;
824 if ((d & 1) == 0)
825 incr -= 1;
826 } else if (rmode == FPSCR_ROUND_TOZERO) {
827 incr = 0;
828 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
829 incr = ~0ULL;
830 }
831
832 if ((rem + incr) < rem && d < 0xffffffff)
833 d += 1;
834 if (d > (0x7fffffff + (vdm.sign != 0))) {
835 d = (0x7fffffff + (vdm.sign != 0));
836 exceptions |= FPSCR_IOC;
837 } else if (rem)
838 exceptions |= FPSCR_IXC;
839
840 if (vdm.sign)
841 d = -d;
842 } else {
843 d = 0;
844 if (vdm.exponent | vdm.significand) {
845 exceptions |= FPSCR_IXC;
846 if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
847 d = 1;
848 else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
849 d = -1;
850 }
851 }
852
853 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
854
855 vfp_put_float(state, (s32)d, sd);
856
857 return exceptions;
858}
859
860static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
861{
862 pr_debug("In %s\n", __FUNCTION__);
863 return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO);
864}
865
866static struct op fops_ext[] = {
867 { vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY
868 { vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS
869 { vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG
870 { vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
871 { NULL, 0 },
872 { NULL, 0 },
873 { NULL, 0 },
874 { NULL, 0 },
875 { vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
876 { vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
877 { vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
878 { vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
879 { NULL, 0 },
880 { NULL, 0 },
881 { NULL, 0 },
882 { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
883 { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
884 { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
885 { NULL, 0 },
886 { NULL, 0 },
887 { NULL, 0 },
888 { NULL, 0 },
889 { NULL, 0 },
890 { NULL, 0 },
891 { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
892 { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
893 { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
894 { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
895};
896
897
898
899
900static u32
901vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
902 struct vfp_double *vdm, u32 fpscr)
903{
904 struct vfp_double *vdp;
905 u32 exceptions = 0;
906 int tn, tm;
907
908 tn = vfp_double_type(vdn);
909 tm = vfp_double_type(vdm);
910
911 if (tn & tm & VFP_INFINITY) {
912 /*
913 * Two infinities. Are they different signs?
914 */
915 if (vdn->sign ^ vdm->sign) {
916 /*
917 * different signs -> invalid
918 */
919 exceptions = FPSCR_IOC;
920 vdp = &vfp_double_default_qnan;
921 } else {
922 /*
923 * same signs -> valid
924 */
925 vdp = vdn;
926 }
927 } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
928 /*
929 * One infinity and one number -> infinity
930 */
931 vdp = vdn;
932 } else {
933 /*
934 * 'n' is a NaN of some type
935 */
936 return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
937 }
938 *vdd = *vdp;
939 return exceptions;
940}
941
942u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_double *vdm, u32 fpscr)
943{
944 u32 exp_diff;
945 u64 m_sig;
946
947 if (vdn->significand & (1ULL << 63) ||
948 vdm->significand & (1ULL << 63)) {
949 pr_info("VFP: bad FP values in %s\n", __func__);
950 vfp_double_dump("VDN", vdn);
951 vfp_double_dump("VDM", vdm);
952 }
953
954 /*
955 * Ensure that 'n' is the largest magnitude number. Note that
956 * if 'n' and 'm' have equal exponents, we do not swap them.
957 * This ensures that NaN propagation works correctly.
958 */
959 if (vdn->exponent < vdm->exponent) {
960 struct vfp_double *t = vdn;
961 vdn = vdm;
962 vdm = t;
963 }
964
965 /*
966 * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
967 * infinity or a NaN here.
968 */
969 if (vdn->exponent == 2047)
970 return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
971
972 /*
973 * We have two proper numbers, where 'vdn' is the larger magnitude.
974 *
975 * Copy 'n' to 'd' before doing the arithmetic.
976 */
977 *vdd = *vdn;
978
979 /*
980 * Align 'm' with the result.
981 */
982 exp_diff = vdn->exponent - vdm->exponent;
983 m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
984
985 /*
986 * If the signs are different, we are really subtracting.
987 */
988 if (vdn->sign ^ vdm->sign) {
989 m_sig = vdn->significand - m_sig;
990 if ((s64)m_sig < 0) {
991 vdd->sign = vfp_sign_negate(vdd->sign);
992 m_sig = -m_sig;
993 } else if (m_sig == 0) {
994 vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
995 FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
996 }
997 } else {
998 m_sig += vdn->significand;
999 }
1000 vdd->significand = m_sig;
1001
1002 return 0;
1003}
1004
1005u32
1006vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
1007 struct vfp_double *vdm, u32 fpscr)
1008{
1009 vfp_double_dump("VDN", vdn);
1010 vfp_double_dump("VDM", vdm);
1011
1012 /*
1013 * Ensure that 'n' is the largest magnitude number. Note that
1014 * if 'n' and 'm' have equal exponents, we do not swap them.
1015 * This ensures that NaN propagation works correctly.
1016 */
1017 if (vdn->exponent < vdm->exponent) {
1018 struct vfp_double *t = vdn;
1019 vdn = vdm;
1020 vdm = t;
1021 pr_debug("VFP: swapping M <-> N\n");
1022 }
1023
1024 vdd->sign = vdn->sign ^ vdm->sign;
1025
1026 /*
1027 * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
1028 */
1029 if (vdn->exponent == 2047) {
1030 if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
1031 return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
1032 if ((vdm->exponent | vdm->significand) == 0) {
1033 *vdd = vfp_double_default_qnan;
1034 return FPSCR_IOC;
1035 }
1036 vdd->exponent = vdn->exponent;
1037 vdd->significand = 0;
1038 return 0;
1039 }
1040
1041 /*
1042 * If 'm' is zero, the result is always zero. In this case,
1043 * 'n' may be zero or a number, but it doesn't matter which.
1044 */
1045 if ((vdm->exponent | vdm->significand) == 0) {
1046 vdd->exponent = 0;
1047 vdd->significand = 0;
1048 return 0;
1049 }
1050
1051 /*
1052 * We add 2 to the destination exponent for the same reason
1053 * as the addition case - though this time we have +1 from
1054 * each input operand.
1055 */
1056 vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
1057 vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
1058
1059 vfp_double_dump("VDD", vdd);
1060 return 0;
1061}
1062
1063#define NEG_MULTIPLY (1 << 0)
1064#define NEG_SUBTRACT (1 << 1)
1065
1066static u32
1067vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, char *func)
1068{
1069 struct vfp_double vdd, vdp, vdn, vdm;
1070 u32 exceptions;
1071
1072 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1073 if (vdn.exponent == 0 && vdn.significand)
1074 vfp_double_normalise_denormal(&vdn);
1075
1076 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1077 if (vdm.exponent == 0 && vdm.significand)
1078 vfp_double_normalise_denormal(&vdm);
1079
1080 exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
1081 if (negate & NEG_MULTIPLY)
1082 vdp.sign = vfp_sign_negate(vdp.sign);
1083
1084 vfp_double_unpack(&vdn, vfp_get_double(state, dd));
1085 if (negate & NEG_SUBTRACT)
1086 vdn.sign = vfp_sign_negate(vdn.sign);
1087
1088 exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
1089
1090 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func);
1091}
1092
1093/*
1094 * Standard operations
1095 */
1096
1097/*
1098 * sd = sd + (sn * sm)
1099 */
1100static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1101{
1102 pr_debug("In %s\n", __FUNCTION__);
1103 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac");
1104}
1105
1106/*
1107 * sd = sd - (sn * sm)
1108 */
1109static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1110{
1111 pr_debug("In %s\n", __FUNCTION__);
1112 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
1113}
1114
1115/*
1116 * sd = -sd + (sn * sm)
1117 */
1118static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1119{
1120 pr_debug("In %s\n", __FUNCTION__);
1121 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
1122}
1123
1124/*
1125 * sd = -sd - (sn * sm)
1126 */
1127static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1128{
1129 pr_debug("In %s\n", __FUNCTION__);
1130 return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
1131}
1132
1133/*
1134 * sd = sn * sm
1135 */
1136static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1137{
1138 struct vfp_double vdd, vdn, vdm;
1139 u32 exceptions;
1140
1141 pr_debug("In %s\n", __FUNCTION__);
1142 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1143 if (vdn.exponent == 0 && vdn.significand)
1144 vfp_double_normalise_denormal(&vdn);
1145
1146 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1147 if (vdm.exponent == 0 && vdm.significand)
1148 vfp_double_normalise_denormal(&vdm);
1149
1150 exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
1151 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul");
1152}
1153
1154/*
1155 * sd = -(sn * sm)
1156 */
1157static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1158{
1159 struct vfp_double vdd, vdn, vdm;
1160 u32 exceptions;
1161
1162 pr_debug("In %s\n", __FUNCTION__);
1163 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1164 if (vdn.exponent == 0 && vdn.significand)
1165 vfp_double_normalise_denormal(&vdn);
1166
1167 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1168 if (vdm.exponent == 0 && vdm.significand)
1169 vfp_double_normalise_denormal(&vdm);
1170
1171 exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
1172 vdd.sign = vfp_sign_negate(vdd.sign);
1173
1174 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul");
1175}
1176
1177/*
1178 * sd = sn + sm
1179 */
1180static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1181{
1182 struct vfp_double vdd, vdn, vdm;
1183 u32 exceptions;
1184
1185 pr_debug("In %s\n", __FUNCTION__);
1186 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1187 if (vdn.exponent == 0 && vdn.significand)
1188 vfp_double_normalise_denormal(&vdn);
1189
1190 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1191 if (vdm.exponent == 0 && vdm.significand)
1192 vfp_double_normalise_denormal(&vdm);
1193
1194 exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
1195
1196 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd");
1197}
1198
1199/*
1200 * sd = sn - sm
1201 */
1202static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1203{
1204 struct vfp_double vdd, vdn, vdm;
1205 u32 exceptions;
1206
1207 pr_debug("In %s\n", __FUNCTION__);
1208 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1209 if (vdn.exponent == 0 && vdn.significand)
1210 vfp_double_normalise_denormal(&vdn);
1211
1212 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1213 if (vdm.exponent == 0 && vdm.significand)
1214 vfp_double_normalise_denormal(&vdm);
1215
1216 /*
1217 * Subtraction is like addition, but with a negated operand.
1218 */
1219 vdm.sign = vfp_sign_negate(vdm.sign);
1220
1221 exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
1222
1223 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub");
1224}
1225
1226/*
1227 * sd = sn / sm
1228 */
1229static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
1230{
1231 struct vfp_double vdd, vdn, vdm;
1232 u32 exceptions = 0;
1233 int tm, tn;
1234
1235 pr_debug("In %s\n", __FUNCTION__);
1236 vfp_double_unpack(&vdn, vfp_get_double(state, dn));
1237 vfp_double_unpack(&vdm, vfp_get_double(state, dm));
1238
1239 vdd.sign = vdn.sign ^ vdm.sign;
1240
1241 tn = vfp_double_type(&vdn);
1242 tm = vfp_double_type(&vdm);
1243
1244 /*
1245 * Is n a NAN?
1246 */
1247 if (tn & VFP_NAN)
1248 goto vdn_nan;
1249
1250 /*
1251 * Is m a NAN?
1252 */
1253 if (tm & VFP_NAN)
1254 goto vdm_nan;
1255
1256 /*
1257 * If n and m are infinity, the result is invalid
1258 * If n and m are zero, the result is invalid
1259 */
1260 if (tm & tn & (VFP_INFINITY|VFP_ZERO))
1261 goto invalid;
1262
1263 /*
1264 * If n is infinity, the result is infinity
1265 */
1266 if (tn & VFP_INFINITY)
1267 goto infinity;
1268
1269 /*
1270 * If m is zero, raise div0 exceptions
1271 */
1272 if (tm & VFP_ZERO)
1273 goto divzero;
1274
1275 /*
1276 * If m is infinity, or n is zero, the result is zero
1277 */
1278 if (tm & VFP_INFINITY || tn & VFP_ZERO)
1279 goto zero;
1280
1281 if (tn & VFP_DENORMAL)
1282 vfp_double_normalise_denormal(&vdn);
1283 if (tm & VFP_DENORMAL)
1284 vfp_double_normalise_denormal(&vdm);
1285
1286 /*
1287 * Ok, we have two numbers, we can perform division.
1288 */
1289 vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
1290 vdm.significand <<= 1;
1291 if (vdm.significand <= (2 * vdn.significand)) {
1292 vdn.significand >>= 1;
1293 vdd.exponent++;
1294 }
1295 vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
1296 if ((vdd.significand & 0x1ff) <= 2) {
1297 u64 termh, terml, remh, reml;
1298 mul64to128(&termh, &terml, vdm.significand, vdd.significand);
1299 sub128(&remh, &reml, vdn.significand, 0, termh, terml);
1300 while ((s64)remh < 0) {
1301 vdd.significand -= 1;
1302 add128(&remh, &reml, remh, reml, 0, vdm.significand);
1303 }
1304 vdd.significand |= (reml != 0);
1305 }
1306 return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
1307
1308vdn_nan:
1309 exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
1310pack:
1311 vfp_put_double(state, vfp_double_pack(&vdd), dd);
1312 return exceptions;
1313
1314vdm_nan:
1315 exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
1316 goto pack;
1317
1318zero:
1319 vdd.exponent = 0;
1320 vdd.significand = 0;
1321 goto pack;
1322
1323divzero:
1324 exceptions = FPSCR_DZC;
1325infinity:
1326 vdd.exponent = 2047;
1327 vdd.significand = 0;
1328 goto pack;
1329
1330invalid:
1331 vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
1332 return FPSCR_IOC;
1333}
1334
1335static struct op fops[] = {
1336 { vfp_double_fmac, 0 },
1337 { vfp_double_fmsc, 0 },
1338 { vfp_double_fmul, 0 },
1339 { vfp_double_fadd, 0 },
1340 { vfp_double_fnmac, 0 },
1341 { vfp_double_fnmsc, 0 },
1342 { vfp_double_fnmul, 0 },
1343 { vfp_double_fsub, 0 },
1344 { vfp_double_fdiv, 0 },
1345};
1346
1347#define FREG_BANK(x) ((x) & 0x0c)
1348#define FREG_IDX(x) ((x) & 3)
1349
1350u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
1351{
1352 u32 op = inst & FOP_MASK;
1353 u32 exceptions = 0;
1354 unsigned int dest;
1355 unsigned int dn = vfp_get_dn(inst);
1356 unsigned int dm;
1357 unsigned int vecitr, veclen, vecstride;
1358 struct op *fop;
1359
1360 pr_debug("In %s\n", __FUNCTION__);
1361 vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
1362
1363 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1364
1365 /*
1366 * fcvtds takes an sN register number as destination, not dN.
1367 * It also always operates on scalars.
1368 */
1369 if (fop->flags & OP_SD)
1370 dest = vfp_get_sd(inst);
1371 else
1372 dest = vfp_get_dd(inst);
1373
1374 /*
1375 * f[us]ito takes a sN operand, not a dN operand.
1376 */
1377 if (fop->flags & OP_SM)
1378 dm = vfp_get_sm(inst);
1379 else
1380 dm = vfp_get_dm(inst);
1381
1382 /*
1383 * If destination bank is zero, vector length is always '1'.
1384 * ARM DDI0100F C5.1.3, C5.3.2.
1385 */
1386 if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
1387 veclen = 0;
1388 else
1389 veclen = fpscr & FPSCR_LENGTH_MASK;
1390
1391 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1392 (veclen >> FPSCR_LENGTH_BIT) + 1);
1393
1394 if (!fop->fn) {
1395 printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst));
1396 goto invalid;
1397 }
1398
1399 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1400 u32 except;
1401 char type;
1402
1403 type = fop->flags & OP_SD ? 's' : 'd';
1404 if (op == FOP_EXT)
1405 pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
1406 vecitr >> FPSCR_LENGTH_BIT,
1407 type, dest, dn, dm);
1408 else
1409 pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
1410 vecitr >> FPSCR_LENGTH_BIT,
1411 type, dest, dn, FOP_TO_IDX(op), dm);
1412
1413 except = fop->fn(state, dest, dn, dm, fpscr);
1414 pr_debug("VFP: itr%d: exceptions=%08x\n",
1415 vecitr >> FPSCR_LENGTH_BIT, except);
1416
1417 exceptions |= except;
1418
1419 /*
1420 * CHECK: It appears to be undefined whether we stop when
1421 * we encounter an exception. We continue.
1422 */
1423 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
1424 dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
1425 if (FREG_BANK(dm) != 0)
1426 dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
1427 }
1428 return exceptions;
1429
1430invalid:
1431 return ~0;
1432}
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:
3709 { 3709 {
3710 fault = check_address_validity(cpu, addr, &phys_addr, 0); 3710 fault = check_address_validity(cpu, addr, &phys_addr, 0);
3711 if (fault) goto MMU_EXCEPTION; 3711 if (fault) goto MMU_EXCEPTION;
3712 fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); 3712 fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d], 32);
3713 if (fault) goto MMU_EXCEPTION; 3713 if (fault) goto MMU_EXCEPTION;
3714 DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d, cpu->ExtReg[inst_cream->d]); 3714 DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d, cpu->ExtReg[inst_cream->d]);
3715 } 3715 }
@@ -3719,13 +3719,13 @@ VFPLABEL_INST:
3719 if (fault) goto MMU_EXCEPTION; 3719 if (fault) goto MMU_EXCEPTION;
3720 3720
3721 /* Check endianness */ 3721 /* Check endianness */
3722 fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d*2], 32); 3722 fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d*2], 32);
3723 if (fault) goto MMU_EXCEPTION; 3723 if (fault) goto MMU_EXCEPTION;
3724 3724
3725 fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); 3725 fault = check_address_validity(cpu, addr + 4, &phys_addr, 0);
3726 if (fault) goto MMU_EXCEPTION; 3726 if (fault) goto MMU_EXCEPTION;
3727 3727
3728 fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[inst_cream->d*2+1], 32); 3728 fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[inst_cream->d*2+1], 32);
3729 if (fault) goto MMU_EXCEPTION; 3729 if (fault) goto MMU_EXCEPTION;
3730 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]); 3730 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]);
3731 } 3731 }
@@ -3926,7 +3926,7 @@ VFPLABEL_INST:
3926 { 3926 {
3927 fault = check_address_validity(cpu, addr, &phys_addr, 0); 3927 fault = check_address_validity(cpu, addr, &phys_addr, 0);
3928 if (fault) goto MMU_EXCEPTION; 3928 if (fault) goto MMU_EXCEPTION;
3929 fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); 3929 fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
3930 if (fault) goto MMU_EXCEPTION; 3930 if (fault) goto MMU_EXCEPTION;
3931 DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]); 3931 DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]);
3932 addr += 4; 3932 addr += 4;
@@ -3936,12 +3936,12 @@ VFPLABEL_INST:
3936 /* Careful of endianness, little by default */ 3936 /* Careful of endianness, little by default */
3937 fault = check_address_validity(cpu, addr, &phys_addr, 0); 3937 fault = check_address_validity(cpu, addr, &phys_addr, 0);
3938 if (fault) goto MMU_EXCEPTION; 3938 if (fault) goto MMU_EXCEPTION;
3939 fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); 3939 fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
3940 if (fault) goto MMU_EXCEPTION; 3940 if (fault) goto MMU_EXCEPTION;
3941 3941
3942 fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); 3942 fault = check_address_validity(cpu, addr + 4, &phys_addr, 0);
3943 if (fault) goto MMU_EXCEPTION; 3943 if (fault) goto MMU_EXCEPTION;
3944 fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); 3944 fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
3945 if (fault) goto MMU_EXCEPTION; 3945 if (fault) goto MMU_EXCEPTION;
3946 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]); 3946 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]);
3947 addr += 8; 3947 addr += 8;
@@ -4048,7 +4048,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
4048 { 4048 {
4049 if (single) 4049 if (single)
4050 { 4050 {
4051 //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); 4051 //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
4052 #if 0 4052 #if 0
4053 phys_addr = get_phys_addr(cpu, bb, Addr, 0); 4053 phys_addr = get_phys_addr(cpu, bb, Addr, 0);
4054 bb = cpu->dyncom_engine->bb; 4054 bb = cpu->dyncom_engine->bb;
@@ -4166,7 +4166,7 @@ VFPLABEL_INST: /* encoding 1 */
4166 fault = check_address_validity(cpu, addr, &phys_addr, 0); 4166 fault = check_address_validity(cpu, addr, &phys_addr, 0);
4167 if (fault) goto MMU_EXCEPTION; 4167 if (fault) goto MMU_EXCEPTION;
4168 4168
4169 fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); 4169 fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
4170 if (fault) goto MMU_EXCEPTION; 4170 if (fault) goto MMU_EXCEPTION;
4171 DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]); 4171 DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]);
4172 addr += 4; 4172 addr += 4;
@@ -4177,13 +4177,13 @@ VFPLABEL_INST: /* encoding 1 */
4177 fault = check_address_validity(cpu, addr, &phys_addr, 0); 4177 fault = check_address_validity(cpu, addr, &phys_addr, 0);
4178 if (fault) goto MMU_EXCEPTION; 4178 if (fault) goto MMU_EXCEPTION;
4179 4179
4180 fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); 4180 fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
4181 if (fault) goto MMU_EXCEPTION; 4181 if (fault) goto MMU_EXCEPTION;
4182 4182
4183 fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); 4183 fault = check_address_validity(cpu, addr + 4, &phys_addr, 0);
4184 if (fault) goto MMU_EXCEPTION; 4184 if (fault) goto MMU_EXCEPTION;
4185 4185
4186 fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); 4186 fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
4187 if (fault) goto MMU_EXCEPTION; 4187 if (fault) goto MMU_EXCEPTION;
4188 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]); 4188 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]);
4189 addr += 8; 4189 addr += 8;
@@ -4304,7 +4304,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
4304 if (single) 4304 if (single)
4305 { 4305 {
4306 4306
4307 //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); 4307 //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
4308 /* if R(i) is R15? */ 4308 /* if R(i) is R15? */
4309 #if 0 4309 #if 0
4310 phys_addr = get_phys_addr(cpu, bb, Addr, 0); 4310 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
4321 else 4321 else
4322 { 4322 {
4323 4323
4324 //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); 4324 //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
4325 #if 0 4325 #if 0
4326 phys_addr = get_phys_addr(cpu, bb, Addr, 0); 4326 phys_addr = get_phys_addr(cpu, bb, Addr, 0);
4327 bb = cpu->dyncom_engine->bb; 4327 bb = cpu->dyncom_engine->bb;
@@ -4332,7 +4332,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
4332 bb = cpu->dyncom_engine->bb; 4332 bb = cpu->dyncom_engine->bb;
4333 //if (fault) goto MMU_EXCEPTION; 4333 //if (fault) goto MMU_EXCEPTION;
4334 4334
4335 //fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); 4335 //fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
4336 #if 0 4336 #if 0
4337 phys_addr = get_phys_addr(cpu, bb, ADD(Addr, CONST(4)), 0); 4337 phys_addr = get_phys_addr(cpu, bb, ADD(Addr, CONST(4)), 0);
4338 bb = cpu->dyncom_engine->bb; 4338 bb = cpu->dyncom_engine->bb;
@@ -4431,7 +4431,7 @@ VFPLABEL_INST:
4431 fault = check_address_validity(cpu, addr, &phys_addr, 1); 4431 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4432 if (fault) goto MMU_EXCEPTION; 4432 if (fault) goto MMU_EXCEPTION;
4433 4433
4434 fault = interpreter_read_memory(core, addr, phys_addr, value1, 32); 4434 fault = interpreter_read_memory(addr, phys_addr, value1, 32);
4435 if (fault) goto MMU_EXCEPTION; 4435 if (fault) goto MMU_EXCEPTION;
4436 DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, value1, addr); 4436 DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, value1, addr);
4437 cpu->ExtReg[inst_cream->d+i] = value1; 4437 cpu->ExtReg[inst_cream->d+i] = value1;
@@ -4443,13 +4443,13 @@ VFPLABEL_INST:
4443 fault = check_address_validity(cpu, addr, &phys_addr, 1); 4443 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4444 if (fault) goto MMU_EXCEPTION; 4444 if (fault) goto MMU_EXCEPTION;
4445 4445
4446 fault = interpreter_read_memory(core, addr, phys_addr, value1, 32); 4446 fault = interpreter_read_memory(addr, phys_addr, value1, 32);
4447 if (fault) goto MMU_EXCEPTION; 4447 if (fault) goto MMU_EXCEPTION;
4448 4448
4449 fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); 4449 fault = check_address_validity(cpu, addr + 4, &phys_addr, 1);
4450 if (fault) goto MMU_EXCEPTION; 4450 if (fault) goto MMU_EXCEPTION;
4451 4451
4452 fault = interpreter_read_memory(core, addr + 4, phys_addr, value2, 32); 4452 fault = interpreter_read_memory(addr + 4, phys_addr, value2, 32);
4453 if (fault) goto MMU_EXCEPTION; 4453 if (fault) goto MMU_EXCEPTION;
4454 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); 4454 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);
4455 cpu->ExtReg[(inst_cream->d+i)*2] = value1; 4455 cpu->ExtReg[(inst_cream->d+i)*2] = value1;
@@ -4682,7 +4682,7 @@ VFPLABEL_INST:
4682 { 4682 {
4683 fault = check_address_validity(cpu, addr, &phys_addr, 1); 4683 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4684 if (fault) goto MMU_EXCEPTION; 4684 if (fault) goto MMU_EXCEPTION;
4685 fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); 4685 fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d], 32);
4686 if (fault) goto MMU_EXCEPTION; 4686 if (fault) goto MMU_EXCEPTION;
4687 DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d, cpu->ExtReg[inst_cream->d], addr); 4687 DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d, cpu->ExtReg[inst_cream->d], addr);
4688 } 4688 }
@@ -4691,12 +4691,12 @@ VFPLABEL_INST:
4691 unsigned int word1, word2; 4691 unsigned int word1, word2;
4692 fault = check_address_validity(cpu, addr, &phys_addr, 1); 4692 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4693 if (fault) goto MMU_EXCEPTION; 4693 if (fault) goto MMU_EXCEPTION;
4694 fault = interpreter_read_memory(core, addr, phys_addr, word1, 32); 4694 fault = interpreter_read_memory(addr, phys_addr, word1, 32);
4695 if (fault) goto MMU_EXCEPTION; 4695 if (fault) goto MMU_EXCEPTION;
4696 4696
4697 fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); 4697 fault = check_address_validity(cpu, addr + 4, &phys_addr, 1);
4698 if (fault) goto MMU_EXCEPTION; 4698 if (fault) goto MMU_EXCEPTION;
4699 fault = interpreter_read_memory(core, addr + 4, phys_addr, word2, 32); 4699 fault = interpreter_read_memory(addr + 4, phys_addr, word2, 32);
4700 if (fault) goto MMU_EXCEPTION; 4700 if (fault) goto MMU_EXCEPTION;
4701 /* Check endianness */ 4701 /* Check endianness */
4702 cpu->ExtReg[inst_cream->d*2] = word1; 4702 cpu->ExtReg[inst_cream->d*2] = word1;
@@ -4923,7 +4923,7 @@ VFPLABEL_INST:
4923 { 4923 {
4924 fault = check_address_validity(cpu, addr, &phys_addr, 1); 4924 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4925 if (fault) goto MMU_EXCEPTION; 4925 if (fault) goto MMU_EXCEPTION;
4926 fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); 4926 fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
4927 if (fault) goto MMU_EXCEPTION; 4927 if (fault) goto MMU_EXCEPTION;
4928 DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, cpu->ExtReg[inst_cream->d+i], addr); 4928 DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, cpu->ExtReg[inst_cream->d+i], addr);
4929 addr += 4; 4929 addr += 4;
@@ -4933,12 +4933,12 @@ VFPLABEL_INST:
4933 /* Careful of endianness, little by default */ 4933 /* Careful of endianness, little by default */
4934 fault = check_address_validity(cpu, addr, &phys_addr, 1); 4934 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4935 if (fault) goto MMU_EXCEPTION; 4935 if (fault) goto MMU_EXCEPTION;
4936 fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); 4936 fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32);
4937 if (fault) goto MMU_EXCEPTION; 4937 if (fault) goto MMU_EXCEPTION;
4938 4938
4939 fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); 4939 fault = check_address_validity(cpu, addr + 4, &phys_addr, 1);
4940 if (fault) goto MMU_EXCEPTION; 4940 if (fault) goto MMU_EXCEPTION;
4941 fault = interpreter_read_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); 4941 fault = interpreter_read_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
4942 if (fault) goto MMU_EXCEPTION; 4942 if (fault) goto MMU_EXCEPTION;
4943 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); 4943 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);
4944 addr += 8; 4944 addr += 8;
@@ -5058,7 +5058,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
5058 if (single) 5058 if (single)
5059 { 5059 {
5060 5060
5061 //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); 5061 //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32);
5062 /* if R(i) is R15? */ 5062 /* if R(i) is R15? */
5063 #if 0 5063 #if 0
5064 phys_addr = get_phys_addr(cpu, bb, Addr, 1); 5064 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
5095 val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); 5095 val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb);
5096 LETFPS((d + i) * 2 + 1, FPBITCAST32(val)); 5096 LETFPS((d + i) * 2 + 1, FPBITCAST32(val));
5097 5097
5098 //fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); 5098 //fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32);
5099 //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]); 5099 //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]);
5100 //addr += 8; 5100 //addr += 8;
5101 Addr = ADD(Addr, CONST(8)); 5101 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 @@
1/*
2 vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction
3 Copyright (C) 2003 Skyeye Develop Group
4 for help please send mail to <skyeye-developer@lists.gro.clinux.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21/*
22 * This code is derived in part from :
23 * - Android kernel
24 * - John R. Housers softfloat library, which
25 * carries the following notice:
26 *
27 * ===========================================================================
28 * This C source file is part of the SoftFloat IEC/IEEE Floating-point
29 * Arithmetic Package, Release 2.
30 *
31 * Written by John R. Hauser. This work was made possible in part by the
32 * International Computer Science Institute, located at Suite 600, 1947 Center
33 * Street, Berkeley, California 94704. Funding was partially provided by the
34 * National Science Foundation under grant MIP-9311980. The original version
35 * of this code was written as part of a project to build a fixed-point vector
36 * processor in collaboration with the University of California at Berkeley,
37 * overseen by Profs. Nelson Morgan and John Wawrzynek. More information
38 * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
39 * arithmetic/softfloat.html'.
40 *
41 * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
42 * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
43 * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
44 * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
45 * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
46 *
47 * Derivative works are acceptable, even for commercial purposes, so long as
48 * (1) they include prominent notice that the work is derivative, and (2) they
49 * include prominent notice akin to these three paragraphs for those parts of
50 * this code that are retained.
51 * ===========================================================================
52 */
53
54#include "core/arm/skyeye_common/vfp/vfp_helper.h"
55#include "core/arm/skyeye_common/vfp/asm_vfp.h"
56#include "core/arm/skyeye_common/vfp/vfp.h"
57
58static struct vfp_single vfp_single_default_qnan = {
59 255,
60 0,
61 VFP_SINGLE_SIGNIFICAND_QNAN,
62};
63
64static void vfp_single_dump(const char *str, struct vfp_single *s)
65{
66 pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
67 str, s->sign != 0, s->exponent, s->significand);
68}
69
70static void vfp_single_normalise_denormal(struct vfp_single *vs)
71{
72 int bits = 31 - fls(vs->significand);
73
74 vfp_single_dump("normalise_denormal: in", vs);
75
76 if (bits) {
77 vs->exponent -= bits - 1;
78 vs->significand <<= bits;
79 }
80
81 vfp_single_dump("normalise_denormal: out", vs);
82}
83
84
85u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func)
86{
87 u32 significand, incr, rmode;
88 int exponent, shift, underflow;
89
90 vfp_single_dump("pack: in", vs);
91
92 /*
93 * Infinities and NaNs are a special case.
94 */
95 if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
96 goto pack;
97
98 /*
99 * Special-case zero.
100 */
101 if (vs->significand == 0) {
102 vs->exponent = 0;
103 goto pack;
104 }
105
106 exponent = vs->exponent;
107 significand = vs->significand;
108
109 /*
110 * Normalise first. Note that we shift the significand up to
111 * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
112 * significant bit.
113 */
114 shift = 32 - fls(significand);
115 if (shift < 32 && shift) {
116 exponent -= shift;
117 significand <<= shift;
118 }
119
120#if 1
121 vs->exponent = exponent;
122 vs->significand = significand;
123 vfp_single_dump("pack: normalised", vs);
124#endif
125
126 /*
127 * Tiny number?
128 */
129 underflow = exponent < 0;
130 if (underflow) {
131 significand = vfp_shiftright32jamming(significand, -exponent);
132 exponent = 0;
133#if 1
134 vs->exponent = exponent;
135 vs->significand = significand;
136 vfp_single_dump("pack: tiny number", vs);
137#endif
138 if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
139 underflow = 0;
140 }
141
142 /*
143 * Select rounding increment.
144 */
145 incr = 0;
146 rmode = fpscr & FPSCR_RMODE_MASK;
147
148 if (rmode == FPSCR_ROUND_NEAREST) {
149 incr = 1 << VFP_SINGLE_LOW_BITS;
150 if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
151 incr -= 1;
152 } else if (rmode == FPSCR_ROUND_TOZERO) {
153 incr = 0;
154 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
155 incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
156
157 pr_debug("VFP: rounding increment = 0x%08x\n", incr);
158
159 /*
160 * Is our rounding going to overflow?
161 */
162 if ((significand + incr) < significand) {
163 exponent += 1;
164 significand = (significand >> 1) | (significand & 1);
165 incr >>= 1;
166#if 1
167 vs->exponent = exponent;
168 vs->significand = significand;
169 vfp_single_dump("pack: overflow", vs);
170#endif
171 }
172
173 /*
174 * If any of the low bits (which will be shifted out of the
175 * number) are non-zero, the result is inexact.
176 */
177 if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
178 exceptions |= FPSCR_IXC;
179
180 /*
181 * Do our rounding.
182 */
183 significand += incr;
184
185 /*
186 * Infinity?
187 */
188 if (exponent >= 254) {
189 exceptions |= FPSCR_OFC | FPSCR_IXC;
190 if (incr == 0) {
191 vs->exponent = 253;
192 vs->significand = 0x7fffffff;
193 } else {
194 vs->exponent = 255; /* infinity */
195 vs->significand = 0;
196 }
197 } else {
198 if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
199 exponent = 0;
200 if (exponent || significand > 0x80000000)
201 underflow = 0;
202 if (underflow)
203 exceptions |= FPSCR_UFC;
204 vs->exponent = exponent;
205 vs->significand = significand >> 1;
206 }
207
208pack:
209 vfp_single_dump("pack: final", vs);
210 {
211 s32 d = vfp_single_pack(vs);
212#if 1
213 pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
214 sd, d, exceptions);
215#endif
216 vfp_put_float(state, d, sd);
217 }
218
219 return exceptions;
220}
221
222/*
223 * Propagate the NaN, setting exceptions if it is signalling.
224 * 'n' is always a NaN. 'm' may be a number, NaN or infinity.
225 */
226static u32
227vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
228 struct vfp_single *vsm, u32 fpscr)
229{
230 struct vfp_single *nan;
231 int tn, tm = 0;
232
233 tn = vfp_single_type(vsn);
234
235 if (vsm)
236 tm = vfp_single_type(vsm);
237
238 if (fpscr & FPSCR_DEFAULT_NAN)
239 /*
240 * Default NaN mode - always returns a quiet NaN
241 */
242 nan = &vfp_single_default_qnan;
243 else {
244 /*
245 * Contemporary mode - select the first signalling
246 * NAN, or if neither are signalling, the first
247 * quiet NAN.
248 */
249 if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
250 nan = vsn;
251 else
252 nan = vsm;
253 /*
254 * Make the NaN quiet.
255 */
256 nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
257 }
258
259 *vsd = *nan;
260
261 /*
262 * If one was a signalling NAN, raise invalid operation.
263 */
264 return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
265}
266
267
268/*
269 * Extended operations
270 */
271static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
272{
273 vfp_put_float(state, vfp_single_packed_abs(m), sd);
274 return 0;
275}
276
277static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
278{
279 vfp_put_float(state, m, sd);
280 return 0;
281}
282
283static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
284{
285 vfp_put_float(state, vfp_single_packed_negate(m), sd);
286 return 0;
287}
288
289static const u16 sqrt_oddadjust[] = {
290 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
291 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
292};
293
294static const u16 sqrt_evenadjust[] = {
295 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
296 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
297};
298
299u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
300{
301 int index;
302 u32 z, a;
303
304 if ((significand & 0xc0000000) != 0x40000000) {
305 pr_debug("VFP: estimate_sqrt: invalid significand\n");
306 }
307
308 a = significand << 1;
309 index = (a >> 27) & 15;
310 if (exponent & 1) {
311 z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
312 z = ((a / z) << 14) + (z << 15);
313 a >>= 1;
314 } else {
315 z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
316 z = a / z + z;
317 z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
318 if (z <= a)
319 return (s32)a >> 1;
320 }
321 {
322 u64 v = (u64)a << 31;
323 do_div(v, z);
324 return (u32)(v + (z >> 1));
325 }
326}
327
328static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
329{
330 struct vfp_single vsm, vsd, *vsp;
331 int ret, tm;
332
333 vfp_single_unpack(&vsm, m);
334 tm = vfp_single_type(&vsm);
335 if (tm & (VFP_NAN|VFP_INFINITY)) {
336 vsp = &vsd;
337
338 if (tm & VFP_NAN)
339 ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
340 else if (vsm.sign == 0) {
341sqrt_copy:
342 vsp = &vsm;
343 ret = 0;
344 } else {
345sqrt_invalid:
346 vsp = &vfp_single_default_qnan;
347 ret = FPSCR_IOC;
348 }
349 vfp_put_float(state, vfp_single_pack(vsp), sd);
350 return ret;
351 }
352
353 /*
354 * sqrt(+/- 0) == +/- 0
355 */
356 if (tm & VFP_ZERO)
357 goto sqrt_copy;
358
359 /*
360 * Normalise a denormalised number
361 */
362 if (tm & VFP_DENORMAL)
363 vfp_single_normalise_denormal(&vsm);
364
365 /*
366 * sqrt(<0) = invalid
367 */
368 if (vsm.sign)
369 goto sqrt_invalid;
370
371 vfp_single_dump("sqrt", &vsm);
372
373 /*
374 * Estimate the square root.
375 */
376 vsd.sign = 0;
377 vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
378 vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
379
380 vfp_single_dump("sqrt estimate", &vsd);
381
382 /*
383 * And now adjust.
384 */
385 if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
386 if (vsd.significand < 2) {
387 vsd.significand = 0xffffffff;
388 } else {
389 u64 term;
390 s64 rem;
391 vsm.significand <<= !(vsm.exponent & 1);
392 term = (u64)vsd.significand * vsd.significand;
393 rem = ((u64)vsm.significand << 32) - term;
394
395 pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
396
397 while (rem < 0) {
398 vsd.significand -= 1;
399 rem += ((u64)vsd.significand << 1) | 1;
400 }
401 vsd.significand |= rem != 0;
402 }
403 }
404 vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
405
406 return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt");
407}
408
409/*
410 * Equal := ZC
411 * Less than := N
412 * Greater than := C
413 * Unordered := CV
414 */
415static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr)
416{
417 s32 d;
418 u32 ret = 0;
419
420 d = vfp_get_float(state, sd);
421 if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
422 ret |= FPSCR_C | FPSCR_V;
423 if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
424 /*
425 * Signalling NaN, or signalling on quiet NaN
426 */
427 ret |= FPSCR_IOC;
428 }
429
430 if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
431 ret |= FPSCR_C | FPSCR_V;
432 if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
433 /*
434 * Signalling NaN, or signalling on quiet NaN
435 */
436 ret |= FPSCR_IOC;
437 }
438
439 if (ret == 0) {
440 if (d == m || vfp_single_packed_abs(d | m) == 0) {
441 /*
442 * equal
443 */
444 ret |= FPSCR_Z | FPSCR_C;
445 } else if (vfp_single_packed_sign(d ^ m)) {
446 /*
447 * different signs
448 */
449 if (vfp_single_packed_sign(d))
450 /*
451 * d is negative, so d < m
452 */
453 ret |= FPSCR_N;
454 else
455 /*
456 * d is positive, so d > m
457 */
458 ret |= FPSCR_C;
459 } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
460 /*
461 * d < m
462 */
463 ret |= FPSCR_N;
464 } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
465 /*
466 * d > m
467 */
468 ret |= FPSCR_C;
469 }
470 }
471 return ret;
472}
473
474static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
475{
476 return vfp_compare(state, sd, 0, m, fpscr);
477}
478
479static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
480{
481 return vfp_compare(state, sd, 1, m, fpscr);
482}
483
484static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
485{
486 return vfp_compare(state, sd, 0, 0, fpscr);
487}
488
489static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
490{
491 return vfp_compare(state, sd, 1, 0, fpscr);
492}
493
494static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ichfly for internal use only
495{
496 struct vfp_single vsm;
497 struct vfp_double vdd;
498 int tm;
499 u32 exceptions = 0;
500
501 vfp_single_unpack(&vsm, m);
502
503 tm = vfp_single_type(&vsm);
504
505 /*
506 * If we have a signalling NaN, signal invalid operation.
507 */
508 if (tm == VFP_SNAN)
509 exceptions = FPSCR_IOC;
510
511 if (tm & VFP_DENORMAL)
512 vfp_single_normalise_denormal(&vsm);
513
514 vdd.sign = vsm.sign;
515 vdd.significand = (u64)vsm.significand << 32;
516
517 /*
518 * If we have an infinity or NaN, the exponent must be 2047.
519 */
520 if (tm & (VFP_INFINITY | VFP_NAN)) {
521 vdd.exponent = 2047;
522 if (tm == VFP_QNAN)
523 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
524 goto pack_nan;
525 }
526 else if (tm & VFP_ZERO)
527 vdd.exponent = 0;
528 else
529 vdd.exponent = vsm.exponent + (1023 - 127);
530pack_nan:
531 vfp_double_normaliseroundintern(state, &vdd, fpscr, exceptions, "fcvtd");
532 return vfp_double_pack(&vdd);
533}
534
535static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr)
536{
537 struct vfp_single vsm;
538 struct vfp_double vdd;
539 int tm;
540 u32 exceptions = 0;
541
542 vfp_single_unpack(&vsm, m);
543
544 tm = vfp_single_type(&vsm);
545
546 /*
547 * If we have a signalling NaN, signal invalid operation.
548 */
549 if (tm == VFP_SNAN)
550 exceptions = FPSCR_IOC;
551
552 if (tm & VFP_DENORMAL)
553 vfp_single_normalise_denormal(&vsm);
554
555 vdd.sign = vsm.sign;
556 vdd.significand = (u64)vsm.significand << 32;
557
558 /*
559 * If we have an infinity or NaN, the exponent must be 2047.
560 */
561 if (tm & (VFP_INFINITY|VFP_NAN)) {
562 vdd.exponent = 2047;
563 if (tm == VFP_QNAN)
564 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
565 goto pack_nan;
566 } else if (tm & VFP_ZERO)
567 vdd.exponent = 0;
568 else
569 vdd.exponent = vsm.exponent + (1023 - 127);
570
571 return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
572
573pack_nan:
574 vfp_put_double(state, vfp_double_pack(&vdd), dd);
575 return exceptions;
576}
577
578static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
579{
580 struct vfp_single vs;
581
582 vs.sign = 0;
583 vs.exponent = 127 + 31 - 1;
584 vs.significand = (u32)m;
585
586 return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito");
587}
588
589static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
590{
591 struct vfp_single vs;
592
593 vs.sign = (m & 0x80000000) >> 16;
594 vs.exponent = 127 + 31 - 1;
595 vs.significand = vs.sign ? -m : m;
596
597 return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito");
598}
599
600static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
601{
602 struct vfp_single vsm;
603 u32 d, exceptions = 0;
604 int rmode = fpscr & FPSCR_RMODE_MASK;
605 int tm;
606
607 vfp_single_unpack(&vsm, m);
608 vfp_single_dump("VSM", &vsm);
609
610 /*
611 * Do we have a denormalised number?
612 */
613 tm = vfp_single_type(&vsm);
614 if (tm & VFP_DENORMAL)
615 exceptions |= FPSCR_IDC;
616
617 if (tm & VFP_NAN)
618 vsm.sign = 0;
619
620 if (vsm.exponent >= 127 + 32) {
621 d = vsm.sign ? 0 : 0xffffffff;
622 exceptions = FPSCR_IOC;
623 } else if (vsm.exponent >= 127 - 1) {
624 int shift = 127 + 31 - vsm.exponent;
625 u32 rem, incr = 0;
626
627 /*
628 * 2^0 <= m < 2^32-2^8
629 */
630 d = (vsm.significand << 1) >> shift;
631 rem = vsm.significand << (33 - shift);
632
633 if (rmode == FPSCR_ROUND_NEAREST) {
634 incr = 0x80000000;
635 if ((d & 1) == 0)
636 incr -= 1;
637 } else if (rmode == FPSCR_ROUND_TOZERO) {
638 incr = 0;
639 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
640 incr = ~0;
641 }
642
643 if ((rem + incr) < rem) {
644 if (d < 0xffffffff)
645 d += 1;
646 else
647 exceptions |= FPSCR_IOC;
648 }
649
650 if (d && vsm.sign) {
651 d = 0;
652 exceptions |= FPSCR_IOC;
653 } else if (rem)
654 exceptions |= FPSCR_IXC;
655 } else {
656 d = 0;
657 if (vsm.exponent | vsm.significand) {
658 exceptions |= FPSCR_IXC;
659 if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
660 d = 1;
661 else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
662 d = 0;
663 exceptions |= FPSCR_IOC;
664 }
665 }
666 }
667
668 pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
669
670 vfp_put_float(state, d, sd);
671
672 return exceptions;
673}
674
675static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
676{
677 return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO);
678}
679
680static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
681{
682 struct vfp_single vsm;
683 u32 d, exceptions = 0;
684 int rmode = fpscr & FPSCR_RMODE_MASK;
685 int tm;
686
687 vfp_single_unpack(&vsm, m);
688 vfp_single_dump("VSM", &vsm);
689
690 /*
691 * Do we have a denormalised number?
692 */
693 tm = vfp_single_type(&vsm);
694 if (vfp_single_type(&vsm) & VFP_DENORMAL)
695 exceptions |= FPSCR_IDC;
696
697 if (tm & VFP_NAN) {
698 d = 0;
699 exceptions |= FPSCR_IOC;
700 } else if (vsm.exponent >= 127 + 32) {
701 /*
702 * m >= 2^31-2^7: invalid
703 */
704 d = 0x7fffffff;
705 if (vsm.sign)
706 d = ~d;
707 exceptions |= FPSCR_IOC;
708 } else if (vsm.exponent >= 127 - 1) {
709 int shift = 127 + 31 - vsm.exponent;
710 u32 rem, incr = 0;
711
712 /* 2^0 <= m <= 2^31-2^7 */
713 d = (vsm.significand << 1) >> shift;
714 rem = vsm.significand << (33 - shift);
715
716 if (rmode == FPSCR_ROUND_NEAREST) {
717 incr = 0x80000000;
718 if ((d & 1) == 0)
719 incr -= 1;
720 } else if (rmode == FPSCR_ROUND_TOZERO) {
721 incr = 0;
722 } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
723 incr = ~0;
724 }
725
726 if ((rem + incr) < rem && d < 0xffffffff)
727 d += 1;
728 if (d > (0x7fffffffu + (vsm.sign != 0))) {
729 d = (0x7fffffffu + (vsm.sign != 0));
730 exceptions |= FPSCR_IOC;
731 } else if (rem)
732 exceptions |= FPSCR_IXC;
733
734 if (vsm.sign)
735 d = 0-d;
736 } else {
737 d = 0;
738 if (vsm.exponent | vsm.significand) {
739 exceptions |= FPSCR_IXC;
740 if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
741 d = 1;
742 else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign)
743 d = -1;
744 }
745 }
746
747 pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
748
749 vfp_put_float(state, (s32)d, sd);
750
751 return exceptions;
752}
753
754static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
755{
756 return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO);
757}
758
759static struct op fops_ext[] = {
760 { vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY
761 { vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS
762 { vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG
763 { vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT
764 { NULL, 0 },
765 { NULL, 0 },
766 { NULL, 0 },
767 { NULL, 0 },
768 { vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP
769 { vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE
770 { vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ
771 { vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ
772 { NULL, 0 },
773 { NULL, 0 },
774 { NULL, 0 },
775 { vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT
776 { vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO
777 { vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO
778 { NULL, 0 },
779 { NULL, 0 },
780 { NULL, 0 },
781 { NULL, 0 },
782 { NULL, 0 },
783 { NULL, 0 },
784 { vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI
785 { vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ
786 { vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI
787 { vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ
788};
789
790
791
792
793
794static u32
795vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
796 struct vfp_single *vsm, u32 fpscr)
797{
798 struct vfp_single *vsp;
799 u32 exceptions = 0;
800 int tn, tm;
801
802 tn = vfp_single_type(vsn);
803 tm = vfp_single_type(vsm);
804
805 if (tn & tm & VFP_INFINITY) {
806 /*
807 * Two infinities. Are they different signs?
808 */
809 if (vsn->sign ^ vsm->sign) {
810 /*
811 * different signs -> invalid
812 */
813 exceptions = FPSCR_IOC;
814 vsp = &vfp_single_default_qnan;
815 } else {
816 /*
817 * same signs -> valid
818 */
819 vsp = vsn;
820 }
821 } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
822 /*
823 * One infinity and one number -> infinity
824 */
825 vsp = vsn;
826 } else {
827 /*
828 * 'n' is a NaN of some type
829 */
830 return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
831 }
832 *vsd = *vsp;
833 return exceptions;
834}
835
836static u32
837vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
838 struct vfp_single *vsm, u32 fpscr)
839{
840 u32 exp_diff, m_sig;
841
842 if (vsn->significand & 0x80000000 ||
843 vsm->significand & 0x80000000) {
844 pr_info("VFP: bad FP values in %s\n", __func__);
845 vfp_single_dump("VSN", vsn);
846 vfp_single_dump("VSM", vsm);
847 }
848
849 /*
850 * Ensure that 'n' is the largest magnitude number. Note that
851 * if 'n' and 'm' have equal exponents, we do not swap them.
852 * This ensures that NaN propagation works correctly.
853 */
854 if (vsn->exponent < vsm->exponent) {
855 struct vfp_single *t = vsn;
856 vsn = vsm;
857 vsm = t;
858 }
859
860 /*
861 * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
862 * infinity or a NaN here.
863 */
864 if (vsn->exponent == 255)
865 return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
866
867 /*
868 * We have two proper numbers, where 'vsn' is the larger magnitude.
869 *
870 * Copy 'n' to 'd' before doing the arithmetic.
871 */
872 *vsd = *vsn;
873
874 /*
875 * Align both numbers.
876 */
877 exp_diff = vsn->exponent - vsm->exponent;
878 m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
879
880 /*
881 * If the signs are different, we are really subtracting.
882 */
883 if (vsn->sign ^ vsm->sign) {
884 m_sig = vsn->significand - m_sig;
885 if ((s32)m_sig < 0) {
886 vsd->sign = vfp_sign_negate(vsd->sign);
887 m_sig = 0-m_sig;
888 } else if (m_sig == 0) {
889 vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
890 FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
891 }
892 } else {
893 m_sig = vsn->significand + m_sig;
894 }
895 vsd->significand = m_sig;
896
897 return 0;
898}
899
900static u32
901vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
902{
903 vfp_single_dump("VSN", vsn);
904 vfp_single_dump("VSM", vsm);
905
906 /*
907 * Ensure that 'n' is the largest magnitude number. Note that
908 * if 'n' and 'm' have equal exponents, we do not swap them.
909 * This ensures that NaN propagation works correctly.
910 */
911 if (vsn->exponent < vsm->exponent) {
912 struct vfp_single *t = vsn;
913 vsn = vsm;
914 vsm = t;
915 pr_debug("VFP: swapping M <-> N\n");
916 }
917
918 vsd->sign = vsn->sign ^ vsm->sign;
919
920 /*
921 * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
922 */
923 if (vsn->exponent == 255) {
924 if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
925 return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
926 if ((vsm->exponent | vsm->significand) == 0) {
927 *vsd = vfp_single_default_qnan;
928 return FPSCR_IOC;
929 }
930 vsd->exponent = vsn->exponent;
931 vsd->significand = 0;
932 return 0;
933 }
934
935 /*
936 * If 'm' is zero, the result is always zero. In this case,
937 * 'n' may be zero or a number, but it doesn't matter which.
938 */
939 if ((vsm->exponent | vsm->significand) == 0) {
940 vsd->exponent = 0;
941 vsd->significand = 0;
942 return 0;
943 }
944
945 /*
946 * We add 2 to the destination exponent for the same reason as
947 * the addition case - though this time we have +1 from each
948 * input operand.
949 */
950 vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
951 vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
952
953 vfp_single_dump("VSD", vsd);
954 return 0;
955}
956
957#define NEG_MULTIPLY (1 << 0)
958#define NEG_SUBTRACT (1 << 1)
959
960static u32
961vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func)
962{
963
964 {
965 struct vfp_single vsd, vsp, vsn, vsm;
966 u32 exceptions;
967 s32 v;
968
969
970
971 v = vfp_get_float(state, sn);
972 pr_debug("VFP: s%u = %08x\n", sn, v);
973 vfp_single_unpack(&vsn, v);
974 if (vsn.exponent == 0 && vsn.significand)
975 vfp_single_normalise_denormal(&vsn);
976
977 vfp_single_unpack(&vsm, m);
978 if (vsm.exponent == 0 && vsm.significand)
979 vfp_single_normalise_denormal(&vsm);
980
981 exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
982
983 if (negate & NEG_MULTIPLY)
984 vsp.sign = vfp_sign_negate(vsp.sign);
985
986 v = vfp_get_float(state, sd);
987 pr_debug("VFP: s%u = %08x\n", sd, v);
988 vfp_single_unpack(&vsn, v);
989 if (negate & NEG_SUBTRACT)
990 vsn.sign = vfp_sign_negate(vsn.sign);
991
992 exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
993
994 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
995 }
996
997 struct vfp_double vsd, vsp, vsn, vsm;
998 u32 exceptions;
999 s32 v;
1000 s64 vd;
1001 s64 md;
1002
1003 v = vfp_get_float(state, sn);
1004 vd = vfp_single_to_doubleintern(state, v, fpscr);
1005 vfp_double_unpack(&vsn, vd);
1006
1007 md = vfp_single_to_doubleintern(state, m, fpscr);
1008 vfp_double_unpack(&vsm, md);
1009
1010 exceptions = vfp_double_multiply(&vsp, &vsn, &vsm, fpscr);
1011 if (negate & NEG_MULTIPLY)
1012 vsp.sign = vfp_sign_negate(vsp.sign);
1013
1014 v = vfp_get_float(state, sd);
1015 vd = vfp_single_to_doubleintern(state, v, fpscr);
1016 vfp_double_unpack(&vsn, vd);
1017
1018 if (negate & NEG_SUBTRACT)
1019 vsn.sign = vfp_sign_negate(vsn.sign);
1020
1021 exceptions |= vfp_double_add(&vsd, &vsn, &vsp, fpscr);
1022
1023 s64 debug = vfp_double_pack(&vsd);
1024
1025 return vfp_double_fcvtsinterncutting(state, sd, &vsd, fpscr);
1026
1027}
1028
1029/*
1030 * Standard operations
1031 */
1032
1033/*
1034 * sd = sd + (sn * sm)
1035 */
1036static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1037{
1038 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
1039 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
1040}
1041
1042/*
1043 * sd = sd - (sn * sm)
1044 */
1045static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1046{
1047 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn);
1048 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
1049}
1050
1051/*
1052 * sd = -sd + (sn * sm)
1053 */
1054static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1055{
1056 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
1057 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
1058}
1059
1060/*
1061 * sd = -sd - (sn * sm)
1062 */
1063static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1064{
1065 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
1066 return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
1067}
1068
1069/*
1070 * sd = sn * sm
1071 */
1072static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1073{
1074 struct vfp_single vsd, vsn, vsm;
1075 u32 exceptions;
1076 s32 n = vfp_get_float(state, sn);
1077
1078 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n);
1079
1080 vfp_single_unpack(&vsn, n);
1081 if (vsn.exponent == 0 && vsn.significand)
1082 vfp_single_normalise_denormal(&vsn);
1083
1084 vfp_single_unpack(&vsm, m);
1085 if (vsm.exponent == 0 && vsm.significand)
1086 vfp_single_normalise_denormal(&vsm);
1087
1088 exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
1089 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul");
1090}
1091
1092/*
1093 * sd = -(sn * sm)
1094 */
1095static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1096{
1097 struct vfp_single vsd, vsn, vsm;
1098 u32 exceptions;
1099 s32 n = vfp_get_float(state, sn);
1100
1101 pr_debug("VFP: s%u = %08x\n", sn, n);
1102
1103 vfp_single_unpack(&vsn, n);
1104 if (vsn.exponent == 0 && vsn.significand)
1105 vfp_single_normalise_denormal(&vsn);
1106
1107 vfp_single_unpack(&vsm, m);
1108 if (vsm.exponent == 0 && vsm.significand)
1109 vfp_single_normalise_denormal(&vsm);
1110
1111 exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
1112 vsd.sign = vfp_sign_negate(vsd.sign);
1113 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul");
1114}
1115
1116/*
1117 * sd = sn + sm
1118 */
1119static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1120{
1121 struct vfp_single vsd, vsn, vsm;
1122 u32 exceptions;
1123 s32 n = vfp_get_float(state, sn);
1124
1125 pr_debug("VFP: s%u = %08x\n", sn, n);
1126
1127 /*
1128 * Unpack and normalise denormals.
1129 */
1130 vfp_single_unpack(&vsn, n);
1131 if (vsn.exponent == 0 && vsn.significand)
1132 vfp_single_normalise_denormal(&vsn);
1133
1134 vfp_single_unpack(&vsm, m);
1135 if (vsm.exponent == 0 && vsm.significand)
1136 vfp_single_normalise_denormal(&vsm);
1137
1138 exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr);
1139
1140 return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd");
1141}
1142
1143/*
1144 * sd = sn - sm
1145 */
1146static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1147{
1148 pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
1149 /*
1150 * Subtraction is addition with one sign inverted.
1151 */
1152 return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr);
1153}
1154
1155/*
1156 * sd = sn / sm
1157 */
1158static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1159{
1160 struct vfp_single vsd, vsn, vsm;
1161 u32 exceptions = 0;
1162 s32 n = vfp_get_float(state, sn);
1163 int tm, tn;
1164
1165 pr_debug("VFP: s%u = %08x\n", sn, n);
1166
1167 vfp_single_unpack(&vsn, n);
1168 vfp_single_unpack(&vsm, m);
1169
1170 vsd.sign = vsn.sign ^ vsm.sign;
1171
1172 tn = vfp_single_type(&vsn);
1173 tm = vfp_single_type(&vsm);
1174
1175 /*
1176 * Is n a NAN?
1177 */
1178 if (tn & VFP_NAN)
1179 goto vsn_nan;
1180
1181 /*
1182 * Is m a NAN?
1183 */
1184 if (tm & VFP_NAN)
1185 goto vsm_nan;
1186
1187 /*
1188 * If n and m are infinity, the result is invalid
1189 * If n and m are zero, the result is invalid
1190 */
1191 if (tm & tn & (VFP_INFINITY|VFP_ZERO))
1192 goto invalid;
1193
1194 /*
1195 * If n is infinity, the result is infinity
1196 */
1197 if (tn & VFP_INFINITY)
1198 goto infinity;
1199
1200 /*
1201 * If m is zero, raise div0 exception
1202 */
1203 if (tm & VFP_ZERO)
1204 goto divzero;
1205
1206 /*
1207 * If m is infinity, or n is zero, the result is zero
1208 */
1209 if (tm & VFP_INFINITY || tn & VFP_ZERO)
1210 goto zero;
1211
1212 if (tn & VFP_DENORMAL)
1213 vfp_single_normalise_denormal(&vsn);
1214 if (tm & VFP_DENORMAL)
1215 vfp_single_normalise_denormal(&vsm);
1216
1217 /*
1218 * Ok, we have two numbers, we can perform division.
1219 */
1220 vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
1221 vsm.significand <<= 1;
1222 if (vsm.significand <= (2 * vsn.significand)) {
1223 vsn.significand >>= 1;
1224 vsd.exponent++;
1225 }
1226 {
1227 u64 significand = (u64)vsn.significand << 32;
1228 do_div(significand, vsm.significand);
1229 vsd.significand = (u32)significand;
1230 }
1231 if ((vsd.significand & 0x3f) == 0)
1232 vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
1233
1234 return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
1235
1236vsn_nan:
1237 exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
1238pack:
1239 vfp_put_float(state, vfp_single_pack(&vsd), sd);
1240 return exceptions;
1241
1242vsm_nan:
1243 exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
1244 goto pack;
1245
1246zero:
1247 vsd.exponent = 0;
1248 vsd.significand = 0;
1249 goto pack;
1250
1251divzero:
1252 exceptions = FPSCR_DZC;
1253infinity:
1254 vsd.exponent = 255;
1255 vsd.significand = 0;
1256 goto pack;
1257
1258invalid:
1259 vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
1260 return FPSCR_IOC;
1261}
1262
1263static struct op fops[] = {
1264 { vfp_single_fmac, 0 },
1265 { vfp_single_fmsc, 0 },
1266 { vfp_single_fmul, 0 },
1267 { vfp_single_fadd, 0 },
1268 { vfp_single_fnmac, 0 },
1269 { vfp_single_fnmsc, 0 },
1270 { vfp_single_fnmul, 0 },
1271 { vfp_single_fsub, 0 },
1272 { vfp_single_fdiv, 0 },
1273};
1274
1275#define FREG_BANK(x) ((x) & 0x18)
1276#define FREG_IDX(x) ((x) & 7)
1277
1278u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
1279{
1280 u32 op = inst & FOP_MASK;
1281 u32 exceptions = 0;
1282 unsigned int dest;
1283 unsigned int sn = vfp_get_sn(inst);
1284 unsigned int sm = vfp_get_sm(inst);
1285 unsigned int vecitr, veclen, vecstride;
1286 struct op *fop;
1287 pr_debug("In %s\n", __FUNCTION__);
1288
1289 vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
1290
1291 fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
1292
1293 /*
1294 * fcvtsd takes a dN register number as destination, not sN.
1295 * Technically, if bit 0 of dd is set, this is an invalid
1296 * instruction. However, we ignore this for efficiency.
1297 * It also only operates on scalars.
1298 */
1299 if (fop->flags & OP_DD)
1300 dest = vfp_get_dd(inst);
1301 else
1302 dest = vfp_get_sd(inst);
1303
1304 /*
1305 * If destination bank is zero, vector length is always '1'.
1306 * ARM DDI0100F C5.1.3, C5.3.2.
1307 */
1308 if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
1309 veclen = 0;
1310 else
1311 veclen = fpscr & FPSCR_LENGTH_MASK;
1312
1313 pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
1314 (veclen >> FPSCR_LENGTH_BIT) + 1);
1315
1316 if (!fop->fn) {
1317 printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]);
1318 exit(-1);
1319 goto invalid;
1320 }
1321
1322 for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
1323 s32 m = vfp_get_float(state, sm);
1324 u32 except;
1325 char type;
1326
1327 type = fop->flags & OP_DD ? 'd' : 's';
1328 if (op == FOP_EXT)
1329 pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
1330 vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
1331 sm, m);
1332 else
1333 pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
1334 vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
1335 FOP_TO_IDX(op), sm, m);
1336
1337 except = fop->fn(state, dest, sn, m, fpscr);
1338 pr_debug("VFP: itr%d: exceptions=%08x\n",
1339 vecitr >> FPSCR_LENGTH_BIT, except);
1340
1341 exceptions |= except;
1342
1343 /*
1344 * CHECK: It appears to be undefined whether we stop when
1345 * we encounter an exception. We continue.
1346 */
1347 dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
1348 sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
1349 if (FREG_BANK(sm) != 0)
1350 sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
1351 }
1352 return exceptions;
1353
1354invalid:
1355 return (u32)-1;
1356}
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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/log.h"
7#include "common/symbols.h"
8
9#include "video_core/video_core.h"
10 6
11#include "core/core.h" 7#include "core/core.h"
12#include "core/mem_map.h" 8
13#include "core/hw/hw.h" 9#include "core/settings.h"
14#include "core/hw/gpu.h"
15#include "core/arm/disassembler/arm_disasm.h" 10#include "core/arm/disassembler/arm_disasm.h"
16#include "core/arm/interpreter/arm_interpreter.h" 11#include "core/arm/interpreter/arm_interpreter.h"
17 12#include "core/arm/dyncom/arm_dyncom.h"
18#include "core/hle/hle.h" 13#include "core/hle/hle.h"
19#include "core/hle/kernel/thread.h" 14#include "core/hle/kernel/thread.h"
15#include "core/hw/hw.h"
20 16
21namespace Core { 17namespace Core {
22 18
@@ -54,9 +50,18 @@ int Init() {
54 NOTICE_LOG(MASTER_LOG, "initialized OK"); 50 NOTICE_LOG(MASTER_LOG, "initialized OK");
55 51
56 g_disasm = new ARM_Disasm(); 52 g_disasm = new ARM_Disasm();
57 g_app_core = new ARM_Interpreter();
58 g_sys_core = new ARM_Interpreter(); 53 g_sys_core = new ARM_Interpreter();
59 54
55 switch (Settings::values.cpu_core) {
56 case CPU_FastInterpreter:
57 g_app_core = new ARM_DynCom();
58 break;
59 case CPU_Interpreter:
60 default:
61 g_app_core = new ARM_Interpreter();
62 break;
63 }
64
60 g_last_ticks = Core::g_app_core->GetTicks(); 65 g_last_ticks = Core::g_app_core->GetTicks();
61 66
62 return 0; 67 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 @@
5#pragma once 5#pragma once
6 6
7#include "core/arm/arm_interface.h" 7#include "core/arm/arm_interface.h"
8#include "core/arm/interpreter/armdefs.h" 8#include "core/arm/skyeye_common/armdefs.h"
9 9
10//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
11 11
12namespace Core { 12namespace Core {
13 13
14enum CPUCore {
15 CPU_Interpreter,
16 CPU_FastInterpreter
17};
18
14extern ARM_Interface* g_app_core; ///< ARM11 application core 19extern ARM_Interface* g_app_core; ///< ARM11 application core
15extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core 20extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core
16 21
@@ -21,13 +26,13 @@ void Start();
21 26
22/** 27/**
23 * Run the core CPU loop 28 * Run the core CPU loop
24 * This function loops for 100 instructions in the CPU before trying to update hardware. This is a 29 * This function runs the core for the specified number of CPU instructions before trying to update
25 * little bit faster than SingleStep, and should be pretty much equivalent. The number of 30 * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not
26 * instructions chosen is fairly arbitrary, however a large number will more drastically affect the 31 * required to do a full dispatch with each instruction. NOTE: the number of instructions requested
27 * frequency of GSP interrupts and likely break things. The point of this is to just loop in the CPU 32 * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is
28 * for more than 1 instruction to reduce overhead and make it a little bit faster... 33 * requested (e.g. on a thread switch).
29 */ 34 */
30void RunLoop(int tight_loop=100); 35void RunLoop(int tight_loop=1000);
31 36
32/// Step the CPU one instruction 37/// Step the CPU one instruction
33void SingleStep(); 38void 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 @@
7#include <atomic> 7#include <atomic>
8#include <mutex> 8#include <mutex>
9 9
10#include "common/msg_handler.h"
11#include "common/chunk_file.h" 10#include "common/chunk_file.h"
11#include "common/msg_handler.h"
12#include "common/string_util.h"
12 13
13#include "core/core_timing.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/core_timing.h"
15 16
16int g_clock_rate_arm11 = 268123480; 17int g_clock_rate_arm11 = 268123480;
17 18
@@ -586,9 +587,10 @@ std::string GetScheduledEventsSummary()
586 const char *name = event_types[ptr->type].name; 587 const char *name = event_types[ptr->type].name;
587 if (!name) 588 if (!name)
588 name = "[unknown]"; 589 name = "[unknown]";
589 char temp[512]; 590
590 sprintf(temp, "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); 591 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)ptr->time,
591 text += temp; 592 (u32)(ptr->userdata >> 32), (u32)(ptr->userdata));
593
592 ptr = ptr->next; 594 ptr = ptr->next;
593 } 595 }
594 return text; 596 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 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/string_util.h"
11#include "common/bit_field.h"
12
13#include "core/file_sys/file.h"
14#include "core/file_sys/directory.h"
8 15
16#include "core/mem_map.h"
9#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
10 18
11//////////////////////////////////////////////////////////////////////////////////////////////////// 19////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -13,6 +21,110 @@
13 21
14namespace FileSys { 22namespace FileSys {
15 23
24// Path string type
25enum LowPathType : u32 {
26 Invalid = 0,
27 Empty = 1,
28 Binary = 2,
29 Char = 3,
30 Wchar = 4
31};
32
33union Mode {
34 u32 hex;
35 BitField<0, 1, u32> read_flag;
36 BitField<1, 1, u32> write_flag;
37 BitField<2, 1, u32> create_flag;
38};
39
40class Path {
41public:
42
43 Path():
44 type(Invalid)
45 {
46 }
47
48 Path(LowPathType type, u32 size, u32 pointer):
49 type(type)
50 {
51 switch (type) {
52 case Binary:
53 {
54 u8* data = Memory::GetPointer(pointer);
55 binary = std::vector<u8>(data, data + size);
56 break;
57 }
58 case Char:
59 {
60 const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
61 string = std::string(data, size - 1); // Data is always null-terminated.
62 break;
63 }
64 case Wchar:
65 {
66 const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer));
67 u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
68 break;
69 }
70 }
71 }
72
73 LowPathType GetType() const {
74 return type;
75 }
76
77 const std::string AsString() const {
78 switch (GetType()) {
79 case Char:
80 return string;
81 case Wchar:
82 return Common::UTF16ToUTF8(u16str);
83 case Empty:
84 return {};
85 default:
86 ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!");
87 return {};
88 }
89 }
90
91 const std::u16string AsU16Str() const {
92 switch (GetType()) {
93 case Char:
94 return Common::UTF8ToUTF16(string);
95 case Wchar:
96 return u16str;
97 case Empty:
98 return {};
99 default:
100 ERROR_LOG(KERNEL, "LowPathType cannot be converted to u16string!");
101 return {};
102 }
103 }
104
105 const std::vector<u8> AsBinary() const {
106 switch (GetType()) {
107 case Binary:
108 return binary;
109 case Char:
110 return std::vector<u8>(string.begin(), string.end());
111 case Wchar:
112 return std::vector<u8>(u16str.begin(), u16str.end());
113 case Empty:
114 return {};
115 default:
116 ERROR_LOG(KERNEL, "LowPathType cannot be converted to binary!");
117 return {};
118 }
119 }
120
121private:
122 LowPathType type;
123 std::vector<u8> binary;
124 std::string string;
125 std::u16string u16str;
126};
127
16class Archive : NonCopyable { 128class Archive : NonCopyable {
17public: 129public:
18 /// Supported archive types 130 /// Supported archive types
@@ -36,6 +148,28 @@ public:
36 virtual IdCode GetIdCode() const = 0; 148 virtual IdCode GetIdCode() const = 0;
37 149
38 /** 150 /**
151 * Open a file specified by its path, using the specified mode
152 * @param path Path relative to the archive
153 * @param mode Mode to open the file with
154 * @return Opened file, or nullptr
155 */
156 virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0;
157
158 /**
159 * Create a directory specified by its path
160 * @param path Path relative to the archive
161 * @return Whether the directory could be created
162 */
163 virtual bool CreateDirectory(const std::string& path) const = 0;
164
165 /**
166 * Open a directory specified by its path
167 * @param path Path relative to the archive
168 * @return Opened directory, or nullptr
169 */
170 virtual std::unique_ptr<Directory> OpenDirectory(const std::string& path) const = 0;
171
172 /**
39 * Read data from the archive 173 * Read data from the archive
40 * @param offset Offset in bytes to start reading data from 174 * @param offset Offset in bytes to start reading data from
41 * @param length Length in bytes of data to read from archive 175 * @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 @@
5#include "common/common_types.h" 5#include "common/common_types.h"
6 6
7#include "core/file_sys/archive_romfs.h" 7#include "core/file_sys/archive_romfs.h"
8#include "core/file_sys/directory_romfs.h"
9#include "core/file_sys/file_romfs.h"
8 10
9//////////////////////////////////////////////////////////////////////////////////////////////////// 11////////////////////////////////////////////////////////////////////////////////////////////////////
10// FileSys namespace 12// FileSys namespace
@@ -22,6 +24,35 @@ Archive_RomFS::~Archive_RomFS() {
22} 24}
23 25
24/** 26/**
27 * Open a file specified by its path, using the specified mode
28 * @param path Path relative to the archive
29 * @param mode Mode to open the file with
30 * @return Opened file, or nullptr
31 */
32std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mode mode) const {
33 return std::unique_ptr<File>(new File_RomFS);
34}
35
36/**
37 * Create a directory specified by its path
38 * @param path Path relative to the archive
39 * @return Whether the directory could be created
40 */
41bool Archive_RomFS::CreateDirectory(const std::string& path) const {
42 ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS.");
43 return false;
44};
45
46/**
47 * Open a directory specified by its path
48 * @param path Path relative to the archive
49 * @return Opened directory, or nullptr
50 */
51std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path) const {
52 return std::unique_ptr<Directory>(new Directory_RomFS);
53}
54
55/**
25 * Read data from the archive 56 * Read data from the archive
26 * @param offset Offset in bytes to start reading data from 57 * @param offset Offset in bytes to start reading data from
27 * @param length Length in bytes of data to read from archive 58 * @param length Length in bytes of data to read from archive
@@ -29,7 +60,7 @@ Archive_RomFS::~Archive_RomFS() {
29 * @return Number of bytes read 60 * @return Number of bytes read
30 */ 61 */
31size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { 62size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {
32 DEBUG_LOG(FILESYS, "called offset=%d, length=%d", offset, length); 63 DEBUG_LOG(FILESYS, "called offset=%llu, length=%d", offset, length);
33 memcpy(buffer, &raw_data[(u32)offset], length); 64 memcpy(buffer, &raw_data[(u32)offset], length);
34 return length; 65 return length;
35} 66}
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:
29 IdCode GetIdCode() const override { return IdCode::RomFS; }; 29 IdCode GetIdCode() const override { return IdCode::RomFS; };
30 30
31 /** 31 /**
32 * Open a file specified by its path, using the specified mode
33 * @param path Path relative to the archive
34 * @param mode Mode to open the file with
35 * @return Opened file, or nullptr
36 */
37 std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override;
38
39 /**
40 * Create a directory specified by its path
41 * @param path Path relative to the archive
42 * @return Whether the directory could be created
43 */
44 bool CreateDirectory(const std::string& path) const override;
45
46 /**
47 * Open a directory specified by its path
48 * @param path Path relative to the archive
49 * @return Opened directory, or nullptr
50 */
51 std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override;
52
53 /**
32 * Read data from the archive 54 * Read data from the archive
33 * @param offset Offset in bytes to start reading data from 55 * @param offset Offset in bytes to start reading data from
34 * @param length Length in bytes of data to read from archive 56 * @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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory_sdmc.h"
12#include "core/file_sys/file_sdmc.h"
13#include "core/settings.h"
14
15////////////////////////////////////////////////////////////////////////////////////////////////////
16// FileSys namespace
17
18namespace FileSys {
19
20Archive_SDMC::Archive_SDMC(const std::string& mount_point) {
21 this->mount_point = mount_point;
22 DEBUG_LOG(FILESYS, "Directory %s set as SDMC.", mount_point.c_str());
23}
24
25Archive_SDMC::~Archive_SDMC() {
26}
27
28/**
29 * Initialize the archive.
30 * @return true if it initialized successfully
31 */
32bool Archive_SDMC::Initialize() {
33 if (!Settings::values.use_virtual_sd) {
34 WARN_LOG(FILESYS, "SDMC disabled by config.");
35 return false;
36 }
37
38 if (!FileUtil::CreateFullPath(mount_point)) {
39 WARN_LOG(FILESYS, "Unable to create SDMC path.");
40 return false;
41 }
42
43 return true;
44}
45
46/**
47 * Open a file specified by its path, using the specified mode
48 * @param path Path relative to the archive
49 * @param mode Mode to open the file with
50 * @return Opened file, or nullptr
51 */
52std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const {
53 DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.c_str(), mode);
54 File_SDMC* file = new File_SDMC(this, path, mode);
55 if (!file->Open())
56 return nullptr;
57 return std::unique_ptr<File>(file);
58}
59
60/**
61 * Create a directory specified by its path
62 * @param path Path relative to the archive
63 * @return Whether the directory could be created
64 */
65bool Archive_SDMC::CreateDirectory(const std::string& path) const {
66 return FileUtil::CreateDir(GetMountPoint() + path);
67}
68
69/**
70 * Open a directory specified by its path
71 * @param path Path relative to the archive
72 * @return Opened directory, or nullptr
73 */
74std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const std::string& path) const {
75 DEBUG_LOG(FILESYS, "called path=%s", path.c_str());
76 Directory_SDMC* directory = new Directory_SDMC(this, path);
77 return std::unique_ptr<Directory>(directory);
78}
79
80/**
81 * Read data from the archive
82 * @param offset Offset in bytes to start reading archive from
83 * @param length Length in bytes to read data from archive
84 * @param buffer Buffer to read data into
85 * @return Number of bytes read
86 */
87size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
88 ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
89 return -1;
90}
91
92/**
93 * Write data to the archive
94 * @param offset Offset in bytes to start writing data to
95 * @param length Length in bytes of data to write to archive
96 * @param buffer Buffer to write data from
97 * @param flush The flush parameters (0 == do not flush)
98 * @return Number of bytes written
99 */
100size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) {
101 ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
102 return -1;
103}
104
105/**
106 * Get the size of the archive in bytes
107 * @return Size of the archive in bytes
108 */
109size_t Archive_SDMC::GetSize() const {
110 ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
111 return 0;
112}
113
114/**
115 * Set the size of the archive in bytes
116 */
117void Archive_SDMC::SetSize(const u64 size) {
118 ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
119}
120
121/**
122 * Getter for the path used for this Archive
123 * @return Mount point of that passthrough archive
124 */
125std::string Archive_SDMC::GetMountPoint() const {
126 return mount_point;
127}
128
129} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/archive.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17/// File system interface to the SDMC archive
18class Archive_SDMC final : public Archive {
19public:
20 Archive_SDMC(const std::string& mount_point);
21 ~Archive_SDMC() override;
22
23 /**
24 * Initialize the archive.
25 * @return true if it initialized successfully
26 */
27 bool Initialize();
28
29 /**
30 * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
31 * @return IdCode of the archive
32 */
33 IdCode GetIdCode() const override { return IdCode::SDMC; };
34
35 /**
36 * Open a file specified by its path, using the specified mode
37 * @param path Path relative to the archive
38 * @param mode Mode to open the file with
39 * @return Opened file, or nullptr
40 */
41 std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override;
42
43 /**
44 * Create a directory specified by its path
45 * @param path Path relative to the archive
46 * @return Whether the directory could be created
47 */
48 bool CreateDirectory(const std::string& path) const override;
49
50 /**
51 * Open a directory specified by its path
52 * @param path Path relative to the archive
53 * @return Opened directory, or nullptr
54 */
55 std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override;
56
57 /**
58 * Read data from the archive
59 * @param offset Offset in bytes to start reading archive from
60 * @param length Length in bytes to read data from archive
61 * @param buffer Buffer to read data into
62 * @return Number of bytes read
63 */
64 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
65
66 /**
67 * Write data to the archive
68 * @param offset Offset in bytes to start writing data to
69 * @param length Length in bytes of data to write to archive
70 * @param buffer Buffer to write data from
71 * @param flush The flush parameters (0 == do not flush)
72 * @return Number of bytes written
73 */
74 size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override;
75
76 /**
77 * Get the size of the archive in bytes
78 * @return Size of the archive in bytes
79 */
80 size_t GetSize() const override;
81
82 /**
83 * Set the size of the archive in bytes
84 */
85 void SetSize(const u64 size) override;
86
87 /**
88 * Getter for the path used for this Archive
89 * @return Mount point of that passthrough archive
90 */
91 std::string GetMountPoint() const;
92
93private:
94 std::string mount_point;
95};
96
97} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8
9#include "common/common_types.h"
10
11#include "core/hle/kernel/kernel.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18// Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format
19const size_t FILENAME_LENGTH = 0x20C / 2;
20struct Entry {
21 char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated)
22 std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated)
23 char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD)
24 std::array<char, 4> extension; // 8.3 file extension (set to spaces for directories, null-terminated)
25 char unknown2; // unknown (always 0x01)
26 char unknown3; // unknown (0x00 or 0x08)
27 char is_directory; // directory flag
28 char is_hidden; // hidden flag
29 char is_archive; // archive flag
30 char is_read_only; // read-only flag
31 u64 file_size; // file size (for files only)
32};
33static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!");
34static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry.");
35static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry.");
36static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry.");
37static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry.");
38
39class Directory : NonCopyable {
40public:
41 Directory() { }
42 virtual ~Directory() { }
43
44 /**
45 * List files contained in the directory
46 * @param count Number of entries to return at once in entries
47 * @param entries Buffer to read data into
48 * @return Number of entries listed
49 */
50 virtual u32 Read(const u32 count, Entry* entries) = 0;
51
52 /**
53 * Close the directory
54 * @return true if the directory closed correctly
55 */
56 virtual bool Close() const = 0;
57};
58
59} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6
7#include "core/file_sys/directory_romfs.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// FileSys namespace
11
12namespace FileSys {
13
14Directory_RomFS::Directory_RomFS() {
15}
16
17Directory_RomFS::~Directory_RomFS() {
18}
19
20/**
21 * List files contained in the directory
22 * @param count Number of entries to return at once in entries
23 * @param entries Buffer to read data into
24 * @return Number of entries listed
25 */
26u32 Directory_RomFS::Read(const u32 count, Entry* entries) {
27 return 0;
28}
29
30/**
31 * Close the directory
32 * @return true if the directory closed correctly
33 */
34bool Directory_RomFS::Close() const {
35 return false;
36}
37
38} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/directory.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17class Directory_RomFS final : public Directory {
18public:
19 Directory_RomFS();
20 ~Directory_RomFS() override;
21
22 /**
23 * List files contained in the directory
24 * @param count Number of entries to return at once in entries
25 * @param entries Buffer to read data into
26 * @return Number of entries listed
27 */
28 u32 Read(const u32 count, Entry* entries) override;
29
30 /**
31 * Close the directory
32 * @return true if the directory closed correctly
33 */
34 bool Close() const override;
35};
36
37} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/directory_sdmc.h"
11#include "core/file_sys/archive_sdmc.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const std::string& path) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive.
21 // For example, opening /../../usr/bin can give the emulated program your installed programs.
22 std::string absolute_path = archive->GetMountPoint() + path;
23 FileUtil::ScanDirectoryTree(absolute_path, directory);
24 children_iterator = directory.children.begin();
25}
26
27Directory_SDMC::~Directory_SDMC() {
28 Close();
29}
30
31/**
32 * List files contained in the directory
33 * @param count Number of entries to return at once in entries
34 * @param entries Buffer to read data into
35 * @return Number of entries listed
36 */
37u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
38 u32 entries_read = 0;
39
40 while (entries_read < count && children_iterator != directory.children.cend()) {
41 const FileUtil::FSTEntry& file = *children_iterator;
42 const std::string& filename = file.virtualName;
43 Entry& entry = entries[entries_read];
44
45 WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
46
47 // TODO(Link Mauve): use a proper conversion to UTF-16.
48 for (int j = 0; j < FILENAME_LENGTH; ++j) {
49 entry.filename[j] = filename[j];
50 if (!filename[j])
51 break;
52 }
53
54 FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
55
56 entry.is_directory = file.isDirectory;
57 entry.is_hidden = (filename[0] == '.');
58 entry.is_read_only = 0;
59 entry.file_size = file.size;
60
61 // We emulate a SD card where the archive bit has never been cleared, as it would be on
62 // most user SD cards.
63 // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
64 // file bit.
65 entry.is_archive = !file.isDirectory;
66
67 ++entries_read;
68 ++children_iterator;
69 }
70 return entries_read;
71}
72
73/**
74 * Close the directory
75 * @return true if the directory closed correctly
76 */
77bool Directory_SDMC::Close() const {
78 return true;
79}
80
81} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/directory.h"
11#include "core/file_sys/archive_sdmc.h"
12#include "core/loader/loader.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19class Directory_SDMC final : public Directory {
20public:
21 Directory_SDMC();
22 Directory_SDMC(const Archive_SDMC* archive, const std::string& path);
23 ~Directory_SDMC() override;
24
25 /**
26 * List files contained in the directory
27 * @param count Number of entries to return at once in entries
28 * @param entries Buffer to read data into
29 * @return Number of entries listed
30 */
31 u32 Read(const u32 count, Entry* entries) override;
32
33 /**
34 * Close the directory
35 * @return true if the directory closed correctly
36 */
37 bool Close() const override;
38
39private:
40 u32 total_entries_in_directory;
41 FileUtil::FSTEntry directory;
42
43 // We need to remember the last entry we returned, so a subsequent call to Read will continue
44 // from the next one. This iterator will always point to the next unread entry.
45 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
46};
47
48} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/hle/kernel/kernel.h"
10
11////////////////////////////////////////////////////////////////////////////////////////////////////
12// FileSys namespace
13
14namespace FileSys {
15
16class File : NonCopyable {
17public:
18 File() { }
19 virtual ~File() { }
20
21 /**
22 * Open the file
23 * @return true if the file opened correctly
24 */
25 virtual bool Open() = 0;
26
27 /**
28 * Read data from the file
29 * @param offset Offset in bytes to start reading data from
30 * @param length Length in bytes of data to read from file
31 * @param buffer Buffer to read data into
32 * @return Number of bytes read
33 */
34 virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0;
35
36 /**
37 * Write data to the file
38 * @param offset Offset in bytes to start writing data to
39 * @param length Length in bytes of data to write to file
40 * @param flush The flush parameters (0 == do not flush)
41 * @param buffer Buffer to read data from
42 * @return Number of bytes written
43 */
44 virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0;
45
46 /**
47 * Get the size of the file in bytes
48 * @return Size of the file in bytes
49 */
50 virtual size_t GetSize() const = 0;
51
52 /**
53 * Set the size of the file in bytes
54 * @param size New size of the file
55 * @return true if successful
56 */
57 virtual bool SetSize(const u64 size) const = 0;
58
59 /**
60 * Close the file
61 * @return true if the file closed correctly
62 */
63 virtual bool Close() const = 0;
64};
65
66} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6
7#include "core/file_sys/file_romfs.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// FileSys namespace
11
12namespace FileSys {
13
14File_RomFS::File_RomFS() {
15}
16
17File_RomFS::~File_RomFS() {
18}
19
20/**
21 * Open the file
22 * @return true if the file opened correctly
23 */
24bool File_RomFS::Open() {
25 return false;
26}
27
28/**
29 * Read data from the file
30 * @param offset Offset in bytes to start reading data from
31 * @param length Length in bytes of data to read from file
32 * @param buffer Buffer to read data into
33 * @return Number of bytes read
34 */
35size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {
36 return -1;
37}
38
39/**
40 * Write data to the file
41 * @param offset Offset in bytes to start writing data to
42 * @param length Length in bytes of data to write to file
43 * @param flush The flush parameters (0 == do not flush)
44 * @param buffer Buffer to read data from
45 * @return Number of bytes written
46 */
47size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
48 return -1;
49}
50
51/**
52 * Get the size of the file in bytes
53 * @return Size of the file in bytes
54 */
55size_t File_RomFS::GetSize() const {
56 return -1;
57}
58
59/**
60 * Set the size of the file in bytes
61 * @param size New size of the file
62 * @return true if successful
63 */
64bool File_RomFS::SetSize(const u64 size) const {
65 return false;
66}
67
68/**
69 * Close the file
70 * @return true if the file closed correctly
71 */
72bool File_RomFS::Close() const {
73 return false;
74}
75
76} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/file.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17class File_RomFS final : public File {
18public:
19 File_RomFS();
20 ~File_RomFS() override;
21
22 /**
23 * Open the file
24 * @return true if the file opened correctly
25 */
26 bool Open() override;
27
28 /**
29 * Read data from the file
30 * @param offset Offset in bytes to start reading data from
31 * @param length Length in bytes of data to read from file
32 * @param buffer Buffer to read data into
33 * @return Number of bytes read
34 */
35 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
36
37 /**
38 * Write data to the file
39 * @param offset Offset in bytes to start writing data to
40 * @param length Length in bytes of data to write to file
41 * @param flush The flush parameters (0 == do not flush)
42 * @param buffer Buffer to read data from
43 * @return Number of bytes written
44 */
45 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
46
47 /**
48 * Get the size of the file in bytes
49 * @return Size of the file in bytes
50 */
51 size_t GetSize() const override;
52
53 /**
54 * Set the size of the file in bytes
55 * @param size New size of the file
56 * @return true if successful
57 */
58 bool SetSize(const u64 size) const override;
59
60 /**
61 * Close the file
62 * @return true if the file closed correctly
63 */
64 bool Close() const override;
65};
66
67} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/file_sdmc.h"
11#include "core/file_sys/archive_sdmc.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18File_SDMC::File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive.
21 // For example, opening /../../etc/passwd can give the emulated program your users list.
22 this->path = archive->GetMountPoint() + path;
23 this->mode.hex = mode.hex;
24}
25
26File_SDMC::~File_SDMC() {
27 Close();
28}
29
30/**
31 * Open the file
32 * @return true if the file opened correctly
33 */
34bool File_SDMC::Open() {
35 if (!mode.create_flag && !FileUtil::Exists(path)) {
36 ERROR_LOG(FILESYS, "Non-existing file %s can’t be open without mode create.", path.c_str());
37 return false;
38 }
39
40 std::string mode_string;
41 if (mode.read_flag && mode.write_flag)
42 mode_string = "w+";
43 else if (mode.read_flag)
44 mode_string = "r";
45 else if (mode.write_flag)
46 mode_string = "w";
47
48 file = new FileUtil::IOFile(path, mode_string.c_str());
49 return true;
50}
51
52/**
53 * Read data from the file
54 * @param offset Offset in bytes to start reading data from
55 * @param length Length in bytes of data to read from file
56 * @param buffer Buffer to read data into
57 * @return Number of bytes read
58 */
59size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
60 file->Seek(offset, SEEK_SET);
61 return file->ReadBytes(buffer, length);
62}
63
64/**
65 * Write data to the file
66 * @param offset Offset in bytes to start writing data to
67 * @param length Length in bytes of data to write to file
68 * @param flush The flush parameters (0 == do not flush)
69 * @param buffer Buffer to read data from
70 * @return Number of bytes written
71 */
72size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
73 file->Seek(offset, SEEK_SET);
74 size_t written = file->WriteBytes(buffer, length);
75 if (flush)
76 file->Flush();
77 return written;
78}
79
80/**
81 * Get the size of the file in bytes
82 * @return Size of the file in bytes
83 */
84size_t File_SDMC::GetSize() const {
85 return static_cast<size_t>(file->GetSize());
86}
87
88/**
89 * Set the size of the file in bytes
90 * @param size New size of the file
91 * @return true if successful
92 */
93bool File_SDMC::SetSize(const u64 size) const {
94 file->Resize(size);
95 file->Flush();
96 return true;
97}
98
99/**
100 * Close the file
101 * @return true if the file closed correctly
102 */
103bool File_SDMC::Close() const {
104 return file->Close();
105}
106
107} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/file.h"
11#include "core/file_sys/archive_sdmc.h"
12#include "core/loader/loader.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19class File_SDMC final : public File {
20public:
21 File_SDMC();
22 File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode);
23 ~File_SDMC() override;
24
25 /**
26 * Open the file
27 * @return true if the file opened correctly
28 */
29 bool Open() override;
30
31 /**
32 * Read data from the file
33 * @param offset Offset in bytes to start reading data from
34 * @param length Length in bytes of data to read from file
35 * @param buffer Buffer to read data into
36 * @return Number of bytes read
37 */
38 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
39
40 /**
41 * Write data to the file
42 * @param offset Offset in bytes to start writing data to
43 * @param length Length in bytes of data to write to file
44 * @param flush The flush parameters (0 == do not flush)
45 * @param buffer Buffer to read data from
46 * @return Number of bytes written
47 */
48 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
49
50 /**
51 * Get the size of the file in bytes
52 * @return Size of the file in bytes
53 */
54 size_t GetSize() const override;
55
56 /**
57 * Set the size of the file in bytes
58 * @param size New size of the file
59 * @return true if successful
60 */
61 bool SetSize(const u64 size) const override;
62
63 /**
64 * Close the file
65 * @return true if the file closed correctly
66 */
67 bool Close() const override;
68
69private:
70 std::string path;
71 Mode mode;
72 FileUtil::IOFile* file;
73};
74
75} // 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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/log.h"
7 6
8#include "core/hle/config_mem.h" 7#include "core/hle/config_mem.h"
9 8
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 @@
5#include "core/hle/coprocessor.h" 5#include "core/hle/coprocessor.h"
6#include "core/hle/hle.h" 6#include "core/hle/hle.h"
7#include "core/mem_map.h" 7#include "core/mem_map.h"
8#include "core/core.h"
9 8
10namespace HLE { 9namespace HLE {
11 10
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9namespace HLE {
10
11/// Coprocessor operations
12enum CoprocessorOperation {
13 DATA_SYNCHRONIZATION_BARRIER = 0xE0,
14 CALL_GET_THREAD_COMMAND_BUFFER = 0xE1,
15};
16
17/// Call an MRC (move to ARM register from coprocessor) instruction in HLE
18s32 CallMRC(u32 instruction);
19
20} // 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 @@
6 6
7#include "core/mem_map.h" 7#include "core/mem_map.h"
8#include "core/hle/hle.h" 8#include "core/hle/hle.h"
9#include "core/hle/svc.h"
10#include "core/hle/kernel/thread.h" 9#include "core/hle/kernel/thread.h"
11#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
12 11
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 {
17 17
18class AddressArbiter : public Object { 18class AddressArbiter : public Object {
19public: 19public:
20 std::string GetTypeName() const { return "Arbiter"; } 20 std::string GetTypeName() const override { return "Arbiter"; }
21 std::string GetName() const { return name; } 21 std::string GetName() const override { return name; }
22 22
23 static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; } 23 static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; }
24 Kernel::HandleType GetHandleType() const { return HandleType::AddressArbiter; } 24 Kernel::HandleType GetHandleType() const override { return HandleType::AddressArbiter; }
25 25
26 std::string name; ///< Name of address arbiter object (optional) 26 std::string name; ///< Name of address arbiter object (optional)
27 27
@@ -30,7 +30,7 @@ public:
30 * @param wait Boolean wait set if current thread should wait as a result of sync operation 30 * @param wait Boolean wait set if current thread should wait as a result of sync operation
31 * @return Result of operation, 0 on success, otherwise error code 31 * @return Result of operation, 0 on success, otherwise error code
32 */ 32 */
33 Result WaitSynchronization(bool* wait) { 33 Result WaitSynchronization(bool* wait) override {
34 // TODO(bunnei): ImplementMe 34 // TODO(bunnei): ImplementMe
35 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 35 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
36 return 0; 36 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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/file_util.h"
6#include "common/math_util.h" 7#include "common/math_util.h"
7 8
8#include "core/file_sys/archive.h" 9#include "core/file_sys/archive.h"
10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory.h"
9#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/archive.h" 13#include "core/hle/kernel/archive.h"
12 14
13//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -30,13 +32,21 @@ enum class FileCommand : u32 {
30 Flush = 0x08090000, 32 Flush = 0x08090000,
31}; 33};
32 34
35// Command to access directory
36enum class DirectoryCommand : u32 {
37 Dummy1 = 0x000100C6,
38 Control = 0x040100C4,
39 Read = 0x08010042,
40 Close = 0x08020000,
41};
42
33class Archive : public Object { 43class Archive : public Object {
34public: 44public:
35 std::string GetTypeName() const { return "Archive"; } 45 std::string GetTypeName() const override { return "Archive"; }
36 std::string GetName() const { return name; } 46 std::string GetName() const override { return name; }
37 47
38 static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; } 48 static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; }
39 Kernel::HandleType GetHandleType() const { return HandleType::Archive; } 49 Kernel::HandleType GetHandleType() const override { return HandleType::Archive; }
40 50
41 std::string name; ///< Name of archive (optional) 51 std::string name; ///< Name of archive (optional)
42 FileSys::Archive* backend; ///< Archive backend interface 52 FileSys::Archive* backend; ///< Archive backend interface
@@ -46,7 +56,7 @@ public:
46 * @param wait Boolean wait set if current thread should wait as a result of sync operation 56 * @param wait Boolean wait set if current thread should wait as a result of sync operation
47 * @return Result of operation, 0 on success, otherwise error code 57 * @return Result of operation, 0 on success, otherwise error code
48 */ 58 */
49 Result SyncRequest(bool* wait) { 59 Result SyncRequest(bool* wait) override {
50 u32* cmd_buff = Service::GetCommandBuffer(); 60 u32* cmd_buff = Service::GetCommandBuffer();
51 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 61 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
52 62
@@ -86,6 +96,13 @@ public:
86 backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); 96 backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32));
87 break; 97 break;
88 } 98 }
99 case FileCommand::Close:
100 {
101 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
102 Kernel::g_object_pool.Destroy<Archive>(GetHandle());
103 CloseArchive(backend->GetIdCode());
104 break;
105 }
89 // Unknown command... 106 // Unknown command...
90 default: 107 default:
91 { 108 {
@@ -102,7 +119,162 @@ public:
102 * @param wait Boolean wait set if current thread should wait as a result of sync operation 119 * @param wait Boolean wait set if current thread should wait as a result of sync operation
103 * @return Result of operation, 0 on success, otherwise error code 120 * @return Result of operation, 0 on success, otherwise error code
104 */ 121 */
105 Result WaitSynchronization(bool* wait) { 122 Result WaitSynchronization(bool* wait) override {
123 // TODO(bunnei): ImplementMe
124 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
125 return 0;
126 }
127};
128
129class File : public Object {
130public:
131 std::string GetTypeName() const override { return "File"; }
132 std::string GetName() const override { return path; }
133
134 static Kernel::HandleType GetStaticHandleType() { return HandleType::File; }
135 Kernel::HandleType GetHandleType() const override { return HandleType::File; }
136
137 std::string path; ///< Path of the file
138 std::unique_ptr<FileSys::File> backend; ///< File backend interface
139
140 /**
141 * Synchronize kernel object
142 * @param wait Boolean wait set if current thread should wait as a result of sync operation
143 * @return Result of operation, 0 on success, otherwise error code
144 */
145 Result SyncRequest(bool* wait) override {
146 u32* cmd_buff = Service::GetCommandBuffer();
147 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
148 switch (cmd) {
149
150 // Read from file...
151 case FileCommand::Read:
152 {
153 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
154 u32 length = cmd_buff[3];
155 u32 address = cmd_buff[5];
156 DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%llx length=%d address=0x%x",
157 GetTypeName().c_str(), GetName().c_str(), offset, length, address);
158 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
159 break;
160 }
161
162 // Write to file...
163 case FileCommand::Write:
164 {
165 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
166 u32 length = cmd_buff[3];
167 u32 flush = cmd_buff[4];
168 u32 address = cmd_buff[6];
169 DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
170 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
171 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
172 break;
173 }
174
175 case FileCommand::GetSize:
176 {
177 DEBUG_LOG(KERNEL, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
178 u64 size = backend->GetSize();
179 cmd_buff[2] = (u32)size;
180 cmd_buff[3] = size >> 32;
181 break;
182 }
183
184 case FileCommand::SetSize:
185 {
186 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
187 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size);
188 backend->SetSize(size);
189 break;
190 }
191
192 case FileCommand::Close:
193 {
194 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
195 Kernel::g_object_pool.Destroy<File>(GetHandle());
196 break;
197 }
198
199 // Unknown command...
200 default:
201 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
202 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that.
203 return -1;
204 }
205 cmd_buff[1] = 0; // No error
206 return 0;
207 }
208
209 /**
210 * Wait for kernel object to synchronize
211 * @param wait Boolean wait set if current thread should wait as a result of sync operation
212 * @return Result of operation, 0 on success, otherwise error code
213 */
214 Result WaitSynchronization(bool* wait) override {
215 // TODO(bunnei): ImplementMe
216 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
217 return 0;
218 }
219};
220
221class Directory : public Object {
222public:
223 std::string GetTypeName() const override { return "Directory"; }
224 std::string GetName() const override { return path; }
225
226 static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; }
227 Kernel::HandleType GetHandleType() const override { return HandleType::Directory; }
228
229 std::string path; ///< Path of the directory
230 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
231
232 /**
233 * Synchronize kernel object
234 * @param wait Boolean wait set if current thread should wait as a result of sync operation
235 * @return Result of operation, 0 on success, otherwise error code
236 */
237 Result SyncRequest(bool* wait) override {
238 u32* cmd_buff = Service::GetCommandBuffer();
239 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
240 switch (cmd) {
241
242 // Read from directory...
243 case DirectoryCommand::Read:
244 {
245 u32 count = cmd_buff[1];
246 u32 address = cmd_buff[3];
247 FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
248 DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count);
249
250 // Number of entries actually read
251 cmd_buff[2] = backend->Read(count, entries);
252 break;
253 }
254
255 case DirectoryCommand::Close:
256 {
257 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
258 Kernel::g_object_pool.Destroy<Directory>(GetHandle());
259 break;
260 }
261
262 // Unknown command...
263 default:
264 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
265 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that.
266 return -1;
267 }
268 cmd_buff[1] = 0; // No error
269 return 0;
270 }
271
272 /**
273 * Wait for kernel object to synchronize
274 * @param wait Boolean wait set if current thread should wait as a result of sync operation
275 * @return Result of operation, 0 on success, otherwise error code
276 */
277 Result WaitSynchronization(bool* wait) override {
106 // TODO(bunnei): ImplementMe 278 // TODO(bunnei): ImplementMe
107 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 279 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
108 return 0; 280 return 0;
@@ -127,6 +299,21 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code) {
127} 299}
128 300
129/** 301/**
302 * Closes an archive
303 * @param id_code IdCode of the archive to open
304 * @return Result of operation, 0 on success, otherwise error code
305 */
306Result CloseArchive(FileSys::Archive::IdCode id_code) {
307 if (1 != g_archive_map.erase(id_code)) {
308 ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code);
309 return -1;
310 }
311
312 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
313 return 0;
314}
315
316/**
130 * Mounts an archive 317 * Mounts an archive
131 * @param archive Pointer to the archive to mount 318 * @param archive Pointer to the archive to mount
132 * @return Result of operation, 0 on success, otherwise error code 319 * @return Result of operation, 0 on success, otherwise error code
@@ -172,9 +359,73 @@ Handle CreateArchive(FileSys::Archive* backend, const std::string& name) {
172 return handle; 359 return handle;
173} 360}
174 361
362/**
363 * Open a File from an Archive
364 * @param archive_handle Handle to an open Archive object
365 * @param path Path to the File inside of the Archive
366 * @param mode Mode under which to open the File
367 * @return Opened File object
368 */
369Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) {
370 File* file = new File;
371 Handle handle = Kernel::g_object_pool.Create(file);
372
373 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
374 file->path = path;
375 file->backend = archive->backend->OpenFile(path, mode);
376
377 if (!file->backend)
378 return 0;
379
380 return handle;
381}
382
383/**
384 * Create a Directory from an Archive
385 * @param archive_handle Handle to an open Archive object
386 * @param path Path to the Directory inside of the Archive
387 * @return Opened Directory object
388 */
389Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) {
390 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
391 if (archive == nullptr)
392 return -1;
393 if (archive->backend->CreateDirectory(path))
394 return 0;
395 return -1;
396}
397
398/**
399 * Open a Directory from an Archive
400 * @param archive_handle Handle to an open Archive object
401 * @param path Path to the Directory inside of the Archive
402 * @return Opened Directory object
403 */
404Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) {
405 Directory* directory = new Directory;
406 Handle handle = Kernel::g_object_pool.Create(directory);
407
408 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
409 directory->path = path;
410 directory->backend = archive->backend->OpenDirectory(path);
411
412 return handle;
413}
414
175/// Initialize archives 415/// Initialize archives
176void ArchiveInit() { 416void ArchiveInit() {
177 g_archive_map.clear(); 417 g_archive_map.clear();
418
419 // TODO(Link Mauve): Add the other archive types (see here for the known types:
420 // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished
421 // archive type is SDMC, so it is the only one getting exposed.
422
423 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
424 auto archive = new FileSys::Archive_SDMC(sdmc_directory);
425 if (archive->Initialize())
426 CreateArchive(archive, "SDMC");
427 else
428 ERROR_LOG(KERNEL, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
178} 429}
179 430
180/// Shutdown archives 431/// 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 {
22Handle OpenArchive(FileSys::Archive::IdCode id_code); 22Handle OpenArchive(FileSys::Archive::IdCode id_code);
23 23
24/** 24/**
25 * Closes an archive
26 * @param id_code IdCode of the archive to open
27 * @return true if it worked fine
28 */
29Result CloseArchive(FileSys::Archive::IdCode id_code);
30
31/**
25 * Creates an Archive 32 * Creates an Archive
26 * @param backend File system backend interface to the archive 33 * @param backend File system backend interface to the archive
27 * @param name Optional name of Archive 34 * @param name Optional name of Archive
@@ -29,6 +36,31 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code);
29 */ 36 */
30Handle CreateArchive(FileSys::Archive* backend, const std::string& name); 37Handle CreateArchive(FileSys::Archive* backend, const std::string& name);
31 38
39/**
40 * Open a File from an Archive
41 * @param archive_handle Handle to an open Archive object
42 * @param path Path to the File inside of the Archive
43 * @param mode Mode under which to open the File
44 * @return Opened File object
45 */
46Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode);
47
48/**
49 * Create a Directory from an Archive
50 * @param archive_handle Handle to an open Archive object
51 * @param path Path to the Directory inside of the Archive
52 * @return Whether creation of directory succeeded
53 */
54Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name);
55
56/**
57 * Open a Directory from an Archive
58 * @param archive_handle Handle to an open Archive object
59 * @param path Path to the Directory inside of the Archive
60 * @return Opened Directory object
61 */
62Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name);
63
32/// Initialize archives 64/// Initialize archives
33void ArchiveInit(); 65void ArchiveInit();
34 66
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 {
16 16
17class Event : public Object { 17class Event : public Object {
18public: 18public:
19 std::string GetTypeName() const { return "Event"; } 19 std::string GetTypeName() const override { return "Event"; }
20 std::string GetName() const { return name; } 20 std::string GetName() const override { return name; }
21 21
22 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } 22 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; }
23 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; } 23 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Event; }
24 24
25 ResetType intitial_reset_type; ///< ResetType specified at Event initialization 25 ResetType intitial_reset_type; ///< ResetType specified at Event initialization
26 ResetType reset_type; ///< Current ResetType 26 ResetType reset_type; ///< Current ResetType
@@ -35,7 +35,7 @@ public:
35 * @param wait Boolean wait set if current thread should wait as a result of sync operation 35 * @param wait Boolean wait set if current thread should wait as a result of sync operation
36 * @return Result of operation, 0 on success, otherwise error code 36 * @return Result of operation, 0 on success, otherwise error code
37 */ 37 */
38 Result WaitSynchronization(bool* wait) { 38 Result WaitSynchronization(bool* wait) override {
39 *wait = locked; 39 *wait = locked;
40 if (locked) { 40 if (locked) {
41 Handle thread = GetCurrentThreadHandle(); 41 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 @@
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string.h>
6
7#include "common/common.h" 5#include "common/common.h"
8 6
9#include "core/core.h" 7#include "core/core.h"
@@ -87,47 +85,8 @@ int ObjectPool::GetCount() {
87} 85}
88 86
89Object* ObjectPool::CreateByIDType(int type) { 87Object* ObjectPool::CreateByIDType(int type) {
90 // Used for save states. This is ugly, but what other way is there? 88 ERROR_LOG(COMMON, "Unimplemented: %d.", type);
91 switch (type) { 89 return nullptr;
92 //case SCE_KERNEL_TMID_Alarm:
93 // return __KernelAlarmObject();
94 //case SCE_KERNEL_TMID_EventFlag:
95 // return __KernelEventFlagObject();
96 //case SCE_KERNEL_TMID_Mbox:
97 // return __KernelMbxObject();
98 //case SCE_KERNEL_TMID_Fpl:
99 // return __KernelMemoryFPLObject();
100 //case SCE_KERNEL_TMID_Vpl:
101 // return __KernelMemoryVPLObject();
102 //case PPSSPP_KERNEL_TMID_PMB:
103 // return __KernelMemoryPMBObject();
104 //case PPSSPP_KERNEL_TMID_Module:
105 // return __KernelModuleObject();
106 //case SCE_KERNEL_TMID_Mpipe:
107 // return __KernelMsgPipeObject();
108 //case SCE_KERNEL_TMID_Mutex:
109 // return __KernelMutexObject();
110 //case SCE_KERNEL_TMID_LwMutex:
111 // return __KernelLwMutexObject();
112 //case SCE_KERNEL_TMID_Semaphore:
113 // return __KernelSemaphoreObject();
114 //case SCE_KERNEL_TMID_Callback:
115 // return __KernelCallbackObject();
116 //case SCE_KERNEL_TMID_Thread:
117 // return __KernelThreadObject();
118 //case SCE_KERNEL_TMID_VTimer:
119 // return __KernelVTimerObject();
120 //case SCE_KERNEL_TMID_Tlspl:
121 // return __KernelTlsplObject();
122 //case PPSSPP_KERNEL_TMID_File:
123 // return __KernelFileNodeObject();
124 //case PPSSPP_KERNEL_TMID_DirList:
125 // return __KernelDirListingObject();
126
127 default:
128 ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
129 return nullptr;
130 }
131} 90}
132 91
133/// Initialize the kernel 92/// 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 {
32 File = 10, 32 File = 10,
33 Semaphore = 11, 33 Semaphore = 11,
34 Archive = 12, 34 Archive = 12,
35 Directory = 13,
35}; 36};
36 37
37enum { 38enum {
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 {
15 15
16class Mutex : public Object { 16class Mutex : public Object {
17public: 17public:
18 std::string GetTypeName() const { return "Mutex"; } 18 std::string GetTypeName() const override { return "Mutex"; }
19 std::string GetName() const { return name; } 19 std::string GetName() const override { return name; }
20 20
21 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } 21 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
22 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } 22 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; }
23 23
24 bool initial_locked; ///< Initial lock state when mutex was created 24 bool initial_locked; ///< Initial lock state when mutex was created
25 bool locked; ///< Current locked state 25 bool locked; ///< Current locked state
@@ -32,7 +32,7 @@ public:
32 * @param wait Boolean wait set if current thread should wait as a result of sync operation 32 * @param wait Boolean wait set if current thread should wait as a result of sync operation
33 * @return Result of operation, 0 on success, otherwise error code 33 * @return Result of operation, 0 on success, otherwise error code
34 */ 34 */
35 Result SyncRequest(bool* wait) { 35 Result SyncRequest(bool* wait) override {
36 // TODO(bunnei): ImplementMe 36 // TODO(bunnei): ImplementMe
37 locked = true; 37 locked = true;
38 return 0; 38 return 0;
@@ -43,7 +43,7 @@ public:
43 * @param wait Boolean wait set if current thread should wait as a result of sync operation 43 * @param wait Boolean wait set if current thread should wait as a result of sync operation
44 * @return Result of operation, 0 on success, otherwise error code 44 * @return Result of operation, 0 on success, otherwise error code
45 */ 45 */
46 Result WaitSynchronization(bool* wait) { 46 Result WaitSynchronization(bool* wait) override {
47 // TODO(bunnei): ImplementMe 47 // TODO(bunnei): ImplementMe
48 *wait = locked; 48 *wait = locked;
49 49
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 {
11 11
12class SharedMemory : public Object { 12class SharedMemory : public Object {
13public: 13public:
14 std::string GetTypeName() const { return "SharedMemory"; } 14 std::string GetTypeName() const override { return "SharedMemory"; }
15 15
16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } 16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; }
17 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; } 17 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; }
18 18
19 /** 19 /**
20 * Wait for kernel object to synchronize 20 * Wait for kernel object to synchronize
21 * @param wait Boolean wait set if current thread should wait as a result of sync operation 21 * @param wait Boolean wait set if current thread should wait as a result of sync operation
22 * @return Result of operation, 0 on success, otherwise error code 22 * @return Result of operation, 0 on success, otherwise error code
23 */ 23 */
24 Result WaitSynchronization(bool* wait) { 24 Result WaitSynchronization(bool* wait) override {
25 // TODO(bunnei): ImplementMe 25 // TODO(bunnei): ImplementMe
26 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 26 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
27 return 0; 27 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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstdio>
7#include <list> 6#include <list>
8#include <map> 7#include <map>
9#include <string>
10#include <vector> 8#include <vector>
11 9
12#include "common/common.h" 10#include "common/common.h"
@@ -15,7 +13,6 @@
15#include "core/core.h" 13#include "core/core.h"
16#include "core/mem_map.h" 14#include "core/mem_map.h"
17#include "core/hle/hle.h" 15#include "core/hle/hle.h"
18#include "core/hle/svc.h"
19#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/kernel.h"
20#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
21 18
@@ -24,11 +21,11 @@ namespace Kernel {
24class Thread : public Kernel::Object { 21class Thread : public Kernel::Object {
25public: 22public:
26 23
27 std::string GetName() const { return name; } 24 std::string GetName() const override { return name; }
28 std::string GetTypeName() const { return "Thread"; } 25 std::string GetTypeName() const override { return "Thread"; }
29 26
30 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } 27 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
31 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } 28 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; }
32 29
33 inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } 30 inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
34 inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } 31 inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
@@ -41,7 +38,7 @@ public:
41 * @param wait Boolean wait set if current thread should wait as a result of sync operation 38 * @param wait Boolean wait set if current thread should wait as a result of sync operation
42 * @return Result of operation, 0 on success, otherwise error code 39 * @return Result of operation, 0 on success, otherwise error code
43 */ 40 */
44 Result WaitSynchronization(bool* wait) { 41 Result WaitSynchronization(bool* wait) override {
45 if (status != THREADSTATUS_DORMANT) { 42 if (status != THREADSTATUS_DORMANT) {
46 Handle thread = GetCurrentThreadHandle(); 43 Handle thread = GetCurrentThreadHandle();
47 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 44 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/ac_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace AC_U
11
12namespace AC_U {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010000, nullptr, "CreateDefaultConfig"},
16 {0x00040006, nullptr, "ConnectAsync"},
17 {0x00050002, nullptr, "GetConnectResult"},
18 {0x00080004, nullptr, "CloseAsync"},
19 {0x00090002, nullptr, "GetCloseResult"},
20 {0x000A0000, nullptr, "GetLastErrorCode"},
21 {0x000D0000, nullptr, "GetWifiStatus"},
22 {0x000E0042, nullptr, "GetCurrentAPInfo"},
23 {0x00100042, nullptr, "GetCurrentNZoneInfo"},
24 {0x00110042, nullptr, "GetNZoneApNumService"},
25 {0x00240042, nullptr, "AddDenyApType "},
26 {0x00270002, nullptr, "GetInfraPriority "},
27 {0x002D0082, nullptr, "SetRequestEulaVersion"},
28 {0x00300004, nullptr, "RegisterDisconnectEvent"},
29 {0x003C0042, nullptr, "GetAPSSIDList"},
30 {0x003E0042, nullptr, "IsConnected "},
31 {0x00400042, nullptr, "SetClientVersion"},
32};
33
34////////////////////////////////////////////////////////////////////////////////////////////////////
35// Interface class
36
37Interface::Interface() {
38 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
39}
40
41Interface::~Interface() {
42}
43
44} // 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 @@
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace HID_User 10// Namespace AC_U
11 11
12// This service is used for interfacing to physical user controls... perhaps "Human Interface 12// socket service "ac:u"
13// Devices"? Uses include game pad controls, accelerometers, gyroscopes, etc.
14 13
15namespace HID_User { 14namespace AC_U {
16 15
17class Interface : public Service::Interface { 16class Interface : public Service::Interface {
18public: 17public:
19
20 Interface(); 18 Interface();
21
22 ~Interface(); 19 ~Interface();
23
24 /** 20 /**
25 * Gets the string port name used by CTROS for the service 21 * Gets the string port name used by CTROS for the service
26 * @return Port name of service 22 * @return Port name of service
27 */ 23 */
28 std::string GetPortName() const { 24 std::string GetPortName() const {
29 return "hid:USER"; 25 return "ac:u";
30 } 26 }
31
32}; 27};
33 28
34} // namespace 29} // 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 @@
8#include "core/hle/hle.h" 8#include "core/hle/hle.h"
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/mutex.h" 10#include "core/hle/kernel/mutex.h"
11#include "core/hle/service/apt.h" 11#include "apt_u.h"
12 12
13//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
14// Namespace APT_U 14// Namespace APT_U
15 15
16namespace APT_U { 16namespace APT_U {
17 17
18static Handle lock_handle = 0;
19
18/// Signals used by APT functions 20/// Signals used by APT functions
19enum class SignalType : u32 { 21enum class SignalType : u32 {
20 None = 0x0, 22 None = 0x0,
@@ -32,15 +34,32 @@ void Initialize(Service::Interface* self) {
32 Kernel::SetEventLocked(cmd_buff[3], true); 34 Kernel::SetEventLocked(cmd_buff[3], true);
33 Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event 35 Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
34 36
37 _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock");
38 Kernel::ReleaseMutex(lock_handle);
39
35 cmd_buff[1] = 0; // No error 40 cmd_buff[1] = 0; // No error
41
36 DEBUG_LOG(KERNEL, "called"); 42 DEBUG_LOG(KERNEL, "called");
37} 43}
38 44
39void GetLockHandle(Service::Interface* self) { 45void GetLockHandle(Service::Interface* self) {
40 u32* cmd_buff = Service::GetCommandBuffer(); 46 u32* cmd_buff = Service::GetCommandBuffer();
41 u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field 47 u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
48
49 if (0 == lock_handle) {
50 // TODO(bunnei): Verify if this is created here or at application boot?
51 lock_handle = Kernel::CreateMutex(false, "APT_U:Lock");
52 Kernel::ReleaseMutex(lock_handle);
53 }
42 cmd_buff[1] = 0; // No error 54 cmd_buff[1] = 0; // No error
43 cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock"); 55
56 // Not sure what these parameters are used for, but retail apps check that they are 0 after
57 // GetLockHandle has been called.
58 cmd_buff[2] = 0;
59 cmd_buff[3] = 0;
60 cmd_buff[4] = 0;
61
62 cmd_buff[5] = lock_handle;
44 DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]); 63 DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
45} 64}
46 65
@@ -59,6 +78,25 @@ void InquireNotification(Service::Interface* self) {
59 WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id); 78 WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id);
60} 79}
61 80
81/**
82 * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state,
83 * from the source process which set the parameters. Once finished, NS will clear a flag in the NS
84 * state so that this command will return an error if this command is used again if parameters were
85 * not set again. This is called when the second Initialize event is triggered. It returns a signal
86 * type indicating why it was triggered.
87 * Inputs:
88 * 1 : AppID
89 * 2 : Parameter buffer size, max size is 0x1000
90 * Outputs:
91 * 1 : Result of function, 0 on success, otherwise error code
92 * 2 : Unknown, for now assume AppID of the process which sent these parameters
93 * 3 : Unknown, for now assume Signal type
94 * 4 : Actual parameter buffer size, this is <= to the the input size
95 * 5 : Value
96 * 6 : Handle from the source process which set the parameters, likely used for shared memory
97 * 7 : Size
98 * 8 : Output parameter buffer ptr
99 */
62void ReceiveParameter(Service::Interface* self) { 100void ReceiveParameter(Service::Interface* self) {
63 u32* cmd_buff = Service::GetCommandBuffer(); 101 u32* cmd_buff = Service::GetCommandBuffer();
64 u32 app_id = cmd_buff[1]; 102 u32 app_id = cmd_buff[1];
@@ -66,13 +104,74 @@ void ReceiveParameter(Service::Interface* self) {
66 cmd_buff[1] = 0; // No error 104 cmd_buff[1] = 0; // No error
67 cmd_buff[2] = 0; 105 cmd_buff[2] = 0;
68 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type 106 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
69 cmd_buff[4] = 0x10; 107 cmd_buff[4] = 0x10; // Parameter buffer size (16)
70 cmd_buff[5] = 0; 108 cmd_buff[5] = 0;
71 cmd_buff[6] = 0; 109 cmd_buff[6] = 0;
72 cmd_buff[7] = 0; 110 cmd_buff[7] = 0;
73 WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 111 WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
74} 112}
75 113
114/**
115 * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter
116 * (except for the word value prior to the output handle), except this will not clear the flag
117 * (except when responseword[3]==8 || responseword[3]==9) in NS state.
118 * Inputs:
119 * 1 : AppID
120 * 2 : Parameter buffer size, max size is 0x1000
121 * Outputs:
122 * 1 : Result of function, 0 on success, otherwise error code
123 * 2 : Unknown, for now assume AppID of the process which sent these parameters
124 * 3 : Unknown, for now assume Signal type
125 * 4 : Actual parameter buffer size, this is <= to the the input size
126 * 5 : Value
127 * 6 : Handle from the source process which set the parameters, likely used for shared memory
128 * 7 : Size
129 * 8 : Output parameter buffer ptr
130 */
131void GlanceParameter(Service::Interface* self) {
132 u32* cmd_buff = Service::GetCommandBuffer();
133 u32 app_id = cmd_buff[1];
134 u32 buffer_size = cmd_buff[2];
135
136 cmd_buff[1] = 0; // No error
137 cmd_buff[2] = 0;
138 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
139 cmd_buff[4] = 0x10; // Parameter buffer size (16)
140 cmd_buff[5] = 0;
141 cmd_buff[6] = 0;
142 cmd_buff[7] = 0;
143
144 WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
145}
146
147/**
148 * APT_U::AppletUtility service function
149 * Inputs:
150 * 1 : Unknown, but clearly used for something
151 * 2 : Buffer 1 size (purpose is unknown)
152 * 3 : Buffer 2 size (purpose is unknown)
153 * 5 : Buffer 1 address (purpose is unknown)
154 * 65 : Buffer 2 address (purpose is unknown)
155 * Outputs:
156 * 1 : Result of function, 0 on success, otherwise error code
157 */
158void AppletUtility(Service::Interface* self) {
159 u32* cmd_buff = Service::GetCommandBuffer();
160
161 // These are from 3dbrew - I'm not really sure what they're used for.
162 u32 unk = cmd_buff[1];
163 u32 buffer1_size = cmd_buff[2];
164 u32 buffer2_size = cmd_buff[3];
165 u32 buffer1_addr = cmd_buff[5];
166 u32 buffer2_addr = cmd_buff[65];
167
168 cmd_buff[1] = 0; // No error
169
170 WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, "
171 "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size,
172 buffer1_addr, buffer2_addr);
173}
174
76const Interface::FunctionInfo FunctionTable[] = { 175const Interface::FunctionInfo FunctionTable[] = {
77 {0x00010040, GetLockHandle, "GetLockHandle"}, 176 {0x00010040, GetLockHandle, "GetLockHandle"},
78 {0x00020080, Initialize, "Initialize"}, 177 {0x00020080, Initialize, "Initialize"},
@@ -87,7 +186,7 @@ const Interface::FunctionInfo FunctionTable[] = {
87 {0x000B0040, InquireNotification, "InquireNotification"}, 186 {0x000B0040, InquireNotification, "InquireNotification"},
88 {0x000C0104, nullptr, "SendParameter"}, 187 {0x000C0104, nullptr, "SendParameter"},
89 {0x000D0080, ReceiveParameter, "ReceiveParameter"}, 188 {0x000D0080, ReceiveParameter, "ReceiveParameter"},
90 {0x000E0080, nullptr, "GlanceParameter"}, 189 {0x000E0080, GlanceParameter, "GlanceParameter"},
91 {0x000F0100, nullptr, "CancelParameter"}, 190 {0x000F0100, nullptr, "CancelParameter"},
92 {0x001000C2, nullptr, "DebugFunc"}, 191 {0x001000C2, nullptr, "DebugFunc"},
93 {0x001100C0, nullptr, "MapProgramIdForDebug"}, 192 {0x001100C0, nullptr, "MapProgramIdForDebug"},
@@ -148,10 +247,12 @@ const Interface::FunctionInfo FunctionTable[] = {
148 {0x00480100, nullptr, "GetProgramInfo"}, 247 {0x00480100, nullptr, "GetProgramInfo"},
149 {0x00490180, nullptr, "Reboot"}, 248 {0x00490180, nullptr, "Reboot"},
150 {0x004A0040, nullptr, "GetCaptureInfo"}, 249 {0x004A0040, nullptr, "GetCaptureInfo"},
151 {0x004B00C2, nullptr, "AppletUtility"}, 250 {0x004B00C2, AppletUtility, "AppletUtility"},
152 {0x004C0000, nullptr, "SetFatalErrDispMode"}, 251 {0x004C0000, nullptr, "SetFatalErrDispMode"},
153 {0x004D0080, nullptr, "GetAppletProgramInfo"}, 252 {0x004D0080, nullptr, "GetAppletProgramInfo"},
154 {0x004E0000, nullptr, "HardwareResetAsync"}, 253 {0x004E0000, nullptr, "HardwareResetAsync"},
254 {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"},
255 {0x00500040, nullptr, "GetApplicationCpuTimeLimit"},
155}; 256};
156 257
157//////////////////////////////////////////////////////////////////////////////////////////////////// 258////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -159,6 +260,8 @@ const Interface::FunctionInfo FunctionTable[] = {
159 260
160Interface::Interface() { 261Interface::Interface() {
161 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 262 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
263
264 lock_handle = 0;
162} 265}
163 266
164Interface::~Interface() { 267Interface::~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:
29 * Gets the string port name used by CTROS for the service 29 * Gets the string port name used by CTROS for the service
30 * @return Port name of service 30 * @return Port name of service
31 */ 31 */
32 std::string GetPortName() const { 32 std::string GetPortName() const override {
33 return "APT:U"; 33 return "APT:U";
34 } 34 }
35}; 35};
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/cfg_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CFG_U
11
12namespace CFG_U {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010082, nullptr, "GetConfigInfoBlk2"},
16 {0x00020000, nullptr, "SecureInfoGetRegion"},
17 {0x00030000, nullptr, "GenHashConsoleUnique"},
18 {0x00040000, nullptr, "GetRegionCanadaUSA"},
19 {0x00050000, nullptr, "GetSystemModel"},
20 {0x00060000, nullptr, "GetModelNintendo2DS"},
21 {0x00070040, nullptr, "unknown"},
22 {0x00080080, nullptr, "unknown"},
23 {0x00090080, nullptr, "GetCountryCodeString"},
24 {0x000A0040, nullptr, "GetCountryCodeID"},
25};
26////////////////////////////////////////////////////////////////////////////////////////////////////
27// Interface class
28
29Interface::Interface() {
30 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
31}
32
33Interface::~Interface() {
34}
35
36} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CFG_U
11
12namespace CFG_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const {
23 return "cfg:u";
24 }
25};
26
27} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/dsp_dsp.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace DSP_DSP
11
12namespace DSP_DSP {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010040, nullptr, "RecvData"},
16 {0x00020040, nullptr, "RecvDataIsReady"},
17 {0x00030080, nullptr, "SendData"},
18 {0x00040040, nullptr, "SendDataIsEmpty"},
19 {0x00070040, nullptr, "WriteReg0x10"},
20 {0x00080000, nullptr, "GetSemaphore"},
21 {0x00090040, nullptr, "ClearSemaphore"},
22 {0x000B0000, nullptr, "CheckSemaphoreRequest"},
23 {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"},
24 {0x000D0082, nullptr, "WriteProcessPipe"},
25 {0x001000C0, nullptr, "ReadPipeIfPossible"},
26 {0x001100C2, nullptr, "LoadComponent"},
27 {0x00120000, nullptr, "UnloadComponent"},
28 {0x00130082, nullptr, "FlushDataCache"},
29 {0x00140082, nullptr, "InvalidateDCache "},
30 {0x00150082, nullptr, "RegisterInterruptEvents"},
31 {0x00160000, nullptr, "GetSemaphoreEventHandle"},
32 {0x00170040, nullptr, "SetSemaphoreMask"},
33 {0x00180040, nullptr, "GetPhysicalAddress"},
34 {0x00190040, nullptr, "GetVirtualAddress" },
35 {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
36 {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
37 {0x001C0082, nullptr, "SetIirFilterEQ"},
38 {0x001F0000, nullptr, "GetHeadphoneStatus"},
39 {0x00210000, nullptr, "GetIsDspOccupied"},
40};
41
42////////////////////////////////////////////////////////////////////////////////////////////////////
43// Interface class
44
45Interface::Interface() {
46 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
47}
48
49Interface::~Interface() {
50}
51
52} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace DSP_DSP
11
12namespace DSP_DSP {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const {
23 return "dsp:DSP";
24 }
25};
26
27} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/err_f.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace ERR_F
11
12namespace ERR_F {
13
14 const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010800, nullptr, "ThrowFatalError"}
16 };
17 ////////////////////////////////////////////////////////////////////////////////////////////////////
18 // Interface class
19
20 Interface::Interface() {
21 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
22 }
23
24 Interface::~Interface() {
25 }
26
27} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace ERR_F
11
12namespace ERR_F {
13
14 class Interface : public Service::Interface {
15 public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const {
23 return "err:f";
24 }
25 };
26
27} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/frd_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace FRD_U
11
12namespace FRD_U {
13
14 const Interface::FunctionInfo FunctionTable[] = {
15 {0x00050000, nullptr, "GetFriendKey"},
16 {0x00080000, nullptr, "GetMyPresence"},
17 {0x00100040, nullptr, "GetPassword"},
18 {0x00190042, nullptr, "GetFriendFavoriteGame"},
19 {0x001A00C4, nullptr, "GetFriendInfo"},
20 {0x001B0080, nullptr, "IsOnFriendList"},
21 {0x001C0042, nullptr, "DecodeLocalFriendCode"},
22 {0x001D0002, nullptr, "SetCurrentlyPlayingText"},
23 {0x00320042, nullptr, "SetClientSdkVersion"}
24 };
25 ////////////////////////////////////////////////////////////////////////////////////////////////////
26 // Interface class
27
28 Interface::Interface() {
29 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
30 }
31
32 Interface::~Interface() {
33 }
34
35} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace FRD_U
11
12namespace FRD_U {
13
14 class Interface : public Service::Interface {
15 public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const {
23 return "frd:u";
24 }
25 };
26
27} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common.h"
6
7#include "core/loader/loader.h"
8#include "core/hle/hle.h"
9#include "core/hle/service/fs.h"
10#include "core/hle/kernel/archive.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// Namespace FS_User
14
15namespace FS_User {
16
17void Initialize(Service::Interface* self) {
18 u32* cmd_buff = Service::GetCommandBuffer();
19 cmd_buff[1] = 0; // No error
20 DEBUG_LOG(KERNEL, "called");
21}
22
23void OpenFileDirectly(Service::Interface* self) {
24 u32* cmd_buff = Service::GetCommandBuffer();
25
26 FileSys::Archive::IdCode arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
27
28 // TODO(bunnei): Properly implement use of these...
29 //u32 transaction = cmd_buff[1];
30 //u32 arch_lowpath_type = cmd_buff[3];
31 //u32 arch_lowpath_sz = cmd_buff[4];
32 //u32 file_lowpath_type = cmd_buff[5];
33 //u32 file_lowpath_sz = cmd_buff[6];
34 //u32 flags = cmd_buff[7];
35 //u32 attr = cmd_buff[8];
36 //u32 arch_lowpath_desc = cmd_buff[9];
37 //u32 arch_lowpath_ptr = cmd_buff[10];
38 //u32 file_lowpath_desc = cmd_buff[11];
39 //u32 file_lowpath_ptr = cmd_buff[12];
40
41 Handle handle = Kernel::OpenArchive(arch_id);
42 if (0 != handle) {
43 cmd_buff[1] = 0; // No error
44 cmd_buff[3] = handle;
45 }
46 DEBUG_LOG(KERNEL, "called");
47}
48
49const Interface::FunctionInfo FunctionTable[] = {
50 {0x000100C6, nullptr, "Dummy1"},
51 {0x040100C4, nullptr, "Control"},
52 {0x08010002, Initialize, "Initialize"},
53 {0x080201C2, nullptr, "OpenFile"},
54 {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
55 {0x08040142, nullptr, "DeleteFile"},
56 {0x08050244, nullptr, "RenameFile"},
57 {0x08060142, nullptr, "DeleteDirectory"},
58 {0x08070142, nullptr, "DeleteDirectoryRecursively"},
59 {0x08080202, nullptr, "CreateFile"},
60 {0x08090182, nullptr, "CreateDirectory"},
61 {0x080A0244, nullptr, "RenameDirectory"},
62 {0x080B0102, nullptr, "OpenDirectory"},
63 {0x080C00C2, nullptr, "OpenArchive"},
64 {0x080D0144, nullptr, "ControlArchive"},
65 {0x080E0080, nullptr, "CloseArchive"},
66 {0x080F0180, nullptr, "FormatThisUserSaveData"},
67 {0x08100200, nullptr, "CreateSystemSaveData"},
68 {0x08110040, nullptr, "DeleteSystemSaveData"},
69 {0x08120080, nullptr, "GetFreeBytes"},
70 {0x08130000, nullptr, "GetCardType"},
71 {0x08140000, nullptr, "GetSdmcArchiveResource"},
72 {0x08150000, nullptr, "GetNandArchiveResource"},
73 {0x08160000, nullptr, "GetSdmcFatfsErro"},
74 {0x08170000, nullptr, "IsSdmcDetected"},
75 {0x08180000, nullptr, "IsSdmcWritable"},
76 {0x08190042, nullptr, "GetSdmcCid"},
77 {0x081A0042, nullptr, "GetNandCid"},
78 {0x081B0000, nullptr, "GetSdmcSpeedInfo"},
79 {0x081C0000, nullptr, "GetNandSpeedInfo"},
80 {0x081D0042, nullptr, "GetSdmcLog"},
81 {0x081E0042, nullptr, "GetNandLog"},
82 {0x081F0000, nullptr, "ClearSdmcLog"},
83 {0x08200000, nullptr, "ClearNandLog"},
84 {0x08210000, nullptr, "CardSlotIsInserted"},
85 {0x08220000, nullptr, "CardSlotPowerOn"},
86 {0x08230000, nullptr, "CardSlotPowerOff"},
87 {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
88 {0x08250040, nullptr, "CardNorDirectCommand"},
89 {0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
90 {0x08270082, nullptr, "CardNorDirectRead"},
91 {0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
92 {0x08290082, nullptr, "CardNorDirectWrite"},
93 {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
94 {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
95 {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
96 {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
97 {0x082E0040, nullptr, "GetProductInfo"},
98 {0x082F0040, nullptr, "GetProgramLaunchInfo"},
99 {0x08300182, nullptr, "CreateExtSaveData"},
100 {0x08310180, nullptr, "CreateSharedExtSaveData"},
101 {0x08320102, nullptr, "ReadExtSaveDataIcon"},
102 {0x08330082, nullptr, "EnumerateExtSaveData"},
103 {0x08340082, nullptr, "EnumerateSharedExtSaveData"},
104 {0x08350080, nullptr, "DeleteExtSaveData"},
105 {0x08360080, nullptr, "DeleteSharedExtSaveData"},
106 {0x08370040, nullptr, "SetCardSpiBaudRate"},
107 {0x08380040, nullptr, "SetCardSpiBusMode"},
108 {0x08390000, nullptr, "SendInitializeInfoTo9"},
109 {0x083A0100, nullptr, "GetSpecialContentIndex"},
110 {0x083B00C2, nullptr, "GetLegacyRomHeader"},
111 {0x083C00C2, nullptr, "GetLegacyBannerData"},
112 {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
113 {0x083E00C2, nullptr, "QueryTotalQuotaSize"},
114 {0x083F00C0, nullptr, "GetExtDataBlockSize"},
115 {0x08400040, nullptr, "AbnegateAccessRight"},
116 {0x08410000, nullptr, "DeleteSdmcRoot"},
117 {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
118 {0x08430000, nullptr, "InitializeCtrFileSystem"},
119 {0x08440000, nullptr, "CreateSeed"},
120 {0x084500C2, nullptr, "GetFormatInfo"},
121 {0x08460102, nullptr, "GetLegacyRomHeader2"},
122 {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
123 {0x08480042, nullptr, "GetSdmcCtrRootPath"},
124 {0x08490040, nullptr, "GetArchiveResource"},
125 {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
126 {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
127 {0x084C0242, nullptr, "FormatSaveData"},
128 {0x084D0102, nullptr, "GetLegacySubBannerData"},
129 {0x084E0342, nullptr, "UpdateSha256Context"},
130 {0x084F0102, nullptr, "ReadSpecialFile"},
131 {0x08500040, nullptr, "GetSpecialFileSize"},
132 {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
133 {0x08610042, nullptr, "InitializeWithSdkVersion"},
134 {0x08620040, nullptr, "SetPriority"},
135 {0x08630000, nullptr, "GetPriority"},
136};
137
138////////////////////////////////////////////////////////////////////////////////////////////////////
139// Interface class
140
141Interface::Interface() {
142 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
143}
144
145Interface::~Interface() {
146}
147
148} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common.h"
6
7#include "fs_user.h"
8#include "common/string_util.h"
9#include "core/settings.h"
10#include "core/hle/kernel/archive.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// Namespace FS_User
14
15namespace FS_User {
16
17// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it
18// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make
19// sure we don't mislead the application into thinking something worked.
20
21void Initialize(Service::Interface* self) {
22 u32* cmd_buff = Service::GetCommandBuffer();
23
24 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
25 // http://3dbrew.org/wiki/FS:Initialize#Request
26 cmd_buff[1] = 0;
27
28 DEBUG_LOG(KERNEL, "called");
29}
30
31void OpenFile(Service::Interface* self) {
32 u32* cmd_buff = Service::GetCommandBuffer();
33
34 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
35 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
36 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
37 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
38 u32 filename_size = cmd_buff[5];
39 FileSys::Mode mode; mode.hex = cmd_buff[6];
40 u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
41 u32 filename_ptr = cmd_buff[9];
42
43 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
44 std::string file_string;
45 switch (file_path.GetType()) {
46 case FileSys::Char:
47 case FileSys::Wchar:
48 file_string = file_path.AsString();
49 break;
50 default:
51 WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead");
52 return;
53 }
54
55 DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s",
56 filename_type, filename_size, mode, attributes, file_string.c_str());
57
58 Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode);
59 if (handle) {
60 cmd_buff[1] = 0;
61 cmd_buff[3] = handle;
62 } else {
63 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str());
64 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
65 cmd_buff[1] = -1;
66 }
67
68 DEBUG_LOG(KERNEL, "called");
69}
70
71void OpenFileDirectly(Service::Interface* self) {
72 u32* cmd_buff = Service::GetCommandBuffer();
73
74 auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
75 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
76 u32 archivename_size = cmd_buff[4];
77 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]);
78 u32 filename_size = cmd_buff[6];
79 FileSys::Mode mode; mode.hex = cmd_buff[7];
80 u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
81 u32 archivename_ptr = cmd_buff[10];
82 u32 filename_ptr = cmd_buff[12];
83
84 DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d file_type=%d file_size=%d file_mode=%d file_attrs=%d",
85 archivename_type, archivename_size, filename_type, filename_size, mode, attributes);
86
87 if (archivename_type != FileSys::Empty) {
88 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
89 cmd_buff[1] = -1;
90 return;
91 }
92
93 // TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it.
94 Handle archive_handle = Kernel::OpenArchive(archive_id);
95 if (archive_handle) {
96 cmd_buff[1] = 0;
97 // cmd_buff[2] isn't used according to 3dmoo's implementation.
98 cmd_buff[3] = archive_handle;
99 } else {
100 ERROR_LOG(KERNEL, "failed to get a handle for archive");
101 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
102 cmd_buff[1] = -1;
103 return;
104 }
105
106 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
107 std::string file_string;
108 switch (file_path.GetType()) {
109 case FileSys::Char:
110 case FileSys::Wchar:
111 file_string = file_path.AsString();
112 break;
113 default:
114 WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead");
115 return;
116 }
117
118 Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode);
119 if (handle) {
120 cmd_buff[1] = 0;
121 cmd_buff[3] = handle;
122 } else {
123 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str());
124 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
125 cmd_buff[1] = -1;
126 }
127
128 DEBUG_LOG(KERNEL, "called");
129}
130
131/*
132 * FS_User::CreateDirectory service function
133 * Inputs:
134 * 2 : Archive handle lower word
135 * 3 : Archive handle upper word
136 * 4 : Directory path string type
137 * 5 : Directory path string size
138 * 8 : Directory path string data
139 * Outputs:
140 * 1 : Result of function, 0 on success, otherwise error code
141 */
142void CreateDirectory(Service::Interface* self) {
143 u32* cmd_buff = Service::GetCommandBuffer();
144
145 // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to
146 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
147 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
148 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
149 u32 dirname_size = cmd_buff[5];
150 u32 dirname_ptr = cmd_buff[8];
151
152 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
153 std::string dir_string;
154 switch (dir_path.GetType()) {
155 case FileSys::Char:
156 case FileSys::Wchar:
157 dir_string = dir_path.AsString();
158 break;
159 default:
160 cmd_buff[1] = -1;
161 return;
162 }
163
164 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str());
165
166 cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_string);
167
168 DEBUG_LOG(KERNEL, "called");
169}
170
171void OpenDirectory(Service::Interface* self) {
172 u32* cmd_buff = Service::GetCommandBuffer();
173
174 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
175 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
176 Handle archive_handle = static_cast<Handle>(cmd_buff[2]);
177 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
178 u32 dirname_size = cmd_buff[4];
179 u32 dirname_ptr = cmd_buff[6];
180
181 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
182 std::string dir_string;
183 switch (dir_path.GetType()) {
184 case FileSys::Char:
185 case FileSys::Wchar:
186 dir_string = dir_path.AsString();
187 break;
188 default:
189 cmd_buff[1] = -1;
190 return;
191 }
192
193 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str());
194
195 Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_string);
196 if (handle) {
197 cmd_buff[1] = 0;
198 cmd_buff[3] = handle;
199 } else {
200 ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str());
201 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
202 cmd_buff[1] = -1;
203 }
204
205 DEBUG_LOG(KERNEL, "called");
206}
207
208void OpenArchive(Service::Interface* self) {
209 u32* cmd_buff = Service::GetCommandBuffer();
210
211 auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]);
212 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
213 u32 archivename_size = cmd_buff[3];
214 u32 archivename_ptr = cmd_buff[5];
215
216 DEBUG_LOG(KERNEL, "type=%d size=%d", archivename_type, archivename_size);
217
218 if (archivename_type != FileSys::Empty) {
219 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
220 cmd_buff[1] = -1;
221 return;
222 }
223
224 Handle handle = Kernel::OpenArchive(archive_id);
225 if (handle) {
226 cmd_buff[1] = 0;
227 // cmd_buff[2] isn't used according to 3dmoo's implementation.
228 cmd_buff[3] = handle;
229 } else {
230 ERROR_LOG(KERNEL, "failed to get a handle for archive");
231 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
232 cmd_buff[1] = -1;
233 }
234
235 DEBUG_LOG(KERNEL, "called");
236}
237
238/*
239* FS_User::IsSdmcDetected service function
240* Outputs:
241* 1 : Result of function, 0 on success, otherwise error code
242* 2 : Whether the Sdmc could be detected
243*/
244void IsSdmcDetected(Service::Interface* self) {
245 u32* cmd_buff = Service::GetCommandBuffer();
246
247 cmd_buff[1] = 0;
248 cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
249
250 DEBUG_LOG(KERNEL, "called");
251}
252
253const Interface::FunctionInfo FunctionTable[] = {
254 {0x000100C6, nullptr, "Dummy1"},
255 {0x040100C4, nullptr, "Control"},
256 {0x08010002, Initialize, "Initialize"},
257 {0x080201C2, OpenFile, "OpenFile"},
258 {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
259 {0x08040142, nullptr, "DeleteFile"},
260 {0x08050244, nullptr, "RenameFile"},
261 {0x08060142, nullptr, "DeleteDirectory"},
262 {0x08070142, nullptr, "DeleteDirectoryRecursively"},
263 {0x08080202, nullptr, "CreateFile"},
264 {0x08090182, CreateDirectory, "CreateDirectory"},
265 {0x080A0244, nullptr, "RenameDirectory"},
266 {0x080B0102, OpenDirectory, "OpenDirectory"},
267 {0x080C00C2, OpenArchive, "OpenArchive"},
268 {0x080D0144, nullptr, "ControlArchive"},
269 {0x080E0080, nullptr, "CloseArchive"},
270 {0x080F0180, nullptr, "FormatThisUserSaveData"},
271 {0x08100200, nullptr, "CreateSystemSaveData"},
272 {0x08110040, nullptr, "DeleteSystemSaveData"},
273 {0x08120080, nullptr, "GetFreeBytes"},
274 {0x08130000, nullptr, "GetCardType"},
275 {0x08140000, nullptr, "GetSdmcArchiveResource"},
276 {0x08150000, nullptr, "GetNandArchiveResource"},
277 {0x08160000, nullptr, "GetSdmcFatfsErro"},
278 {0x08170000, IsSdmcDetected, "IsSdmcDetected"},
279 {0x08180000, nullptr, "IsSdmcWritable"},
280 {0x08190042, nullptr, "GetSdmcCid"},
281 {0x081A0042, nullptr, "GetNandCid"},
282 {0x081B0000, nullptr, "GetSdmcSpeedInfo"},
283 {0x081C0000, nullptr, "GetNandSpeedInfo"},
284 {0x081D0042, nullptr, "GetSdmcLog"},
285 {0x081E0042, nullptr, "GetNandLog"},
286 {0x081F0000, nullptr, "ClearSdmcLog"},
287 {0x08200000, nullptr, "ClearNandLog"},
288 {0x08210000, nullptr, "CardSlotIsInserted"},
289 {0x08220000, nullptr, "CardSlotPowerOn"},
290 {0x08230000, nullptr, "CardSlotPowerOff"},
291 {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
292 {0x08250040, nullptr, "CardNorDirectCommand"},
293 {0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
294 {0x08270082, nullptr, "CardNorDirectRead"},
295 {0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
296 {0x08290082, nullptr, "CardNorDirectWrite"},
297 {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
298 {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
299 {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
300 {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
301 {0x082E0040, nullptr, "GetProductInfo"},
302 {0x082F0040, nullptr, "GetProgramLaunchInfo"},
303 {0x08300182, nullptr, "CreateExtSaveData"},
304 {0x08310180, nullptr, "CreateSharedExtSaveData"},
305 {0x08320102, nullptr, "ReadExtSaveDataIcon"},
306 {0x08330082, nullptr, "EnumerateExtSaveData"},
307 {0x08340082, nullptr, "EnumerateSharedExtSaveData"},
308 {0x08350080, nullptr, "DeleteExtSaveData"},
309 {0x08360080, nullptr, "DeleteSharedExtSaveData"},
310 {0x08370040, nullptr, "SetCardSpiBaudRate"},
311 {0x08380040, nullptr, "SetCardSpiBusMode"},
312 {0x08390000, nullptr, "SendInitializeInfoTo9"},
313 {0x083A0100, nullptr, "GetSpecialContentIndex"},
314 {0x083B00C2, nullptr, "GetLegacyRomHeader"},
315 {0x083C00C2, nullptr, "GetLegacyBannerData"},
316 {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
317 {0x083E00C2, nullptr, "QueryTotalQuotaSize"},
318 {0x083F00C0, nullptr, "GetExtDataBlockSize"},
319 {0x08400040, nullptr, "AbnegateAccessRight"},
320 {0x08410000, nullptr, "DeleteSdmcRoot"},
321 {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
322 {0x08430000, nullptr, "InitializeCtrFileSystem"},
323 {0x08440000, nullptr, "CreateSeed"},
324 {0x084500C2, nullptr, "GetFormatInfo"},
325 {0x08460102, nullptr, "GetLegacyRomHeader2"},
326 {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
327 {0x08480042, nullptr, "GetSdmcCtrRootPath"},
328 {0x08490040, nullptr, "GetArchiveResource"},
329 {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
330 {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
331 {0x084C0242, nullptr, "FormatSaveData"},
332 {0x084D0102, nullptr, "GetLegacySubBannerData"},
333 {0x084E0342, nullptr, "UpdateSha256Context"},
334 {0x084F0102, nullptr, "ReadSpecialFile"},
335 {0x08500040, nullptr, "GetSpecialFileSize"},
336 {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
337 {0x08610042, nullptr, "InitializeWithSdkVersion"},
338 {0x08620040, nullptr, "SetPriority"},
339 {0x08630000, nullptr, "GetPriority"},
340};
341
342////////////////////////////////////////////////////////////////////////////////////////////////////
343// Interface class
344
345Interface::Interface() {
346 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
347}
348
349Interface::~Interface() {
350}
351
352} // 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:
23 * Gets the string port name used by CTROS for the service 23 * Gets the string port name used by CTROS for the service
24 * @return Port name of service 24 * @return Port name of service
25 */ 25 */
26 std::string GetPortName() const { 26 std::string GetPortName() const override {
27 return "fs:USER"; 27 return "fs:USER";
28 } 28 }
29}; 29};
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 @@
7#include "common/bit_field.h" 7#include "common/bit_field.h"
8 8
9#include "core/mem_map.h" 9#include "core/mem_map.h"
10#include "core/hle/hle.h"
11#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
12#include "core/hle/kernel/shared_memory.h" 11#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/service/gsp.h" 12#include "gsp_gpu.h"
14#include "core/hw/gpu.h" 13#include "core/hw/gpu.h"
15 14
16#include "video_core/gpu_debugger.h" 15#include "video_core/gpu_debugger.h"
@@ -359,6 +358,7 @@ const Interface::FunctionInfo FunctionTable[] = {
359 {0x001C0040, nullptr, "SetLedForceOff"}, 358 {0x001C0040, nullptr, "SetLedForceOff"},
360 {0x001D0040, nullptr, "SetTestCommand"}, 359 {0x001D0040, nullptr, "SetTestCommand"},
361 {0x001E0080, nullptr, "SetInternalPriorities"}, 360 {0x001E0080, nullptr, "SetInternalPriorities"},
361 {0x001F0082, nullptr, "StoreDataCache"},
362}; 362};
363 363
364//////////////////////////////////////////////////////////////////////////////////////////////////// 364////////////////////////////////////////////////////////////////////////////////////////////////////
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:
167 * Gets the string port name used by CTROS for the service 167 * Gets the string port name used by CTROS for the service
168 * @return Port name of service 168 * @return Port name of service
169 */ 169 */
170 std::string GetPortName() const { 170 std::string GetPortName() const override {
171 return "gsp::Gpu"; 171 return "gsp::Gpu";
172 } 172 }
173 173
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6
7#include "core/hle/hle.h"
8#include "core/hle/kernel/event.h"
9#include "core/hle/kernel/shared_memory.h"
10#include "core/hle/service/hid.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// Namespace HID_User
14
15namespace HID_User {
16
17Handle g_shared_mem = 0; ///< Handle to shared memory region designated to HID_User service
18
19/**
20 * HID_User::GetIPCHandles service function
21 * Inputs:
22 * None
23 * Outputs:
24 * 1 : Result of function, 0 on success, otherwise error code
25 * 2 : Unused
26 * 3 : Handle to HID_User shared memory
27 * 4 : Event signaled by HID_User
28 * 5 : Event signaled by HID_User
29 * 6 : Event signaled by HID_User
30 * 7 : Gyroscope event
31 * 8 : Event signaled by HID_User
32 */
33void GetIPCHandles(Service::Interface* self) {
34 u32* cmd_buff = Service::GetCommandBuffer();
35
36 cmd_buff[1] = 0; // No error
37 cmd_buff[3] = g_shared_mem;
38 cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventA");
39 cmd_buff[5] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventB");
40 cmd_buff[6] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventC");
41 cmd_buff[7] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope");
42 cmd_buff[8] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventD");
43
44 DEBUG_LOG(KERNEL, "called");
45}
46
47const Interface::FunctionInfo FunctionTable[] = {
48 {0x000A0000, GetIPCHandles, "GetIPCHandles"},
49 {0x000B0000, nullptr, "StartAnalogStickCalibration"},
50 {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
51 {0x00110000, nullptr, "EnableAccelerometer"},
52 {0x00120000, nullptr, "DisableAccelerometer"},
53 {0x00130000, nullptr, "EnableGyroscopeLow"},
54 {0x00140000, nullptr, "DisableGyroscopeLow"},
55 {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
56 {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"},
57 {0x00170000, nullptr, "GetSoundVolume"},
58};
59
60////////////////////////////////////////////////////////////////////////////////////////////////////
61// Interface class
62
63Interface::Interface() {
64 g_shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object
65
66 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
67}
68
69Interface::~Interface() {
70}
71
72} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6
7#include "core/hle/hle.h"
8#include "core/hle/kernel/event.h"
9#include "core/hle/kernel/shared_memory.h"
10#include "hid_user.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// Namespace HID_User
14
15namespace HID_User {
16
17// Handle to shared memory region designated to HID_User service
18static Handle shared_mem = 0;
19
20// Event handles
21static Handle event_pad_or_touch_1 = 0;
22static Handle event_pad_or_touch_2 = 0;
23static Handle event_accelerometer = 0;
24static Handle event_gyroscope = 0;
25static Handle event_debug_pad = 0;
26
27// Next Pad state update information
28static PadState next_state = {{0}};
29static u32 next_index = 0;
30static s16 next_circle_x = 0;
31static s16 next_circle_y = 0;
32
33/**
34 * Gets a pointer to the PadData structure inside HID shared memory
35 */
36static inline PadData* GetPadData() {
37 if (0 == shared_mem)
38 return nullptr;
39
40 return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0));
41}
42
43/**
44 * Circle Pad from keys.
45 *
46 * This is implemented as "pushed all the way to an edge (max) or centered (0)".
47 *
48 * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions.
49 */
50void UpdateNextCirclePadState() {
51 static const s16 max_value = 0x9C;
52 next_circle_x = next_state.circle_left ? -max_value : 0x0;
53 next_circle_x += next_state.circle_right ? max_value : 0x0;
54 next_circle_y = next_state.circle_down ? -max_value : 0x0;
55 next_circle_y += next_state.circle_up ? max_value : 0x0;
56}
57
58/**
59 * Sets a Pad state (button or button combo) as pressed
60 */
61void PadButtonPress(PadState pad_state) {
62 next_state.hex |= pad_state.hex;
63 UpdateNextCirclePadState();
64}
65
66/**
67 * Sets a Pad state (button or button combo) as released
68 */
69void PadButtonRelease(PadState pad_state) {
70 next_state.hex &= ~pad_state.hex;
71 UpdateNextCirclePadState();
72}
73
74/**
75 * Called after all Pad changes to be included in this update have been made,
76 * including both Pad key changes and analog circle Pad changes.
77 */
78void PadUpdateComplete() {
79 PadData* pad_data = GetPadData();
80
81 if (pad_data == nullptr) {
82 return;
83 }
84
85 // Update PadData struct
86 pad_data->current_state.hex = next_state.hex;
87 pad_data->index = next_index;
88 next_index = (next_index + 1) % pad_data->entries.size();
89
90 // Get the previous Pad state
91 u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size();
92 PadState old_state = pad_data->entries[last_entry_index].current_state;
93
94 // Compute bitmask with 1s for bits different from the old state
95 PadState changed;
96 changed.hex = (next_state.hex ^ old_state.hex);
97
98 // Compute what was added
99 PadState additions;
100 additions.hex = changed.hex & next_state.hex;
101
102 // Compute what was removed
103 PadState removals;
104 removals.hex = changed.hex & old_state.hex;
105
106 // Get the current Pad entry
107 PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index];
108
109 // Update entry properties
110 current_pad_entry->current_state.hex = next_state.hex;
111 current_pad_entry->delta_additions.hex = additions.hex;
112 current_pad_entry->delta_removals.hex = removals.hex;
113
114 // Set circle Pad
115 current_pad_entry->circle_pad_x = next_circle_x;
116 current_pad_entry->circle_pad_y = next_circle_y;
117
118 // If we just updated index 0, provide a new timestamp
119 if (pad_data->index == 0) {
120 pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks;
121 pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks();
122 }
123
124 // Signal both handles when there's an update to Pad or touch
125 Kernel::SignalEvent(event_pad_or_touch_1);
126 Kernel::SignalEvent(event_pad_or_touch_2);
127}
128
129
130// TODO(peachum):
131// Add a method for setting analog input from joystick device for the circle Pad.
132//
133// This method should:
134// * Be called after both PadButton<Press, Release>().
135// * Be called before PadUpdateComplete()
136// * Set current PadEntry.circle_pad_<axis> using analog data
137// * Set PadData.raw_circle_pad_data
138// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41
139// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41
140// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41
141// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
142
143
144/**
145 * HID_User::GetIPCHandles service function
146 * Inputs:
147 * None
148 * Outputs:
149 * 1 : Result of function, 0 on success, otherwise error code
150 * 2 : Unused
151 * 3 : Handle to HID_User shared memory
152 * 4 : Event signaled by HID_User
153 * 5 : Event signaled by HID_User
154 * 6 : Event signaled by HID_User
155 * 7 : Gyroscope event
156 * 8 : Event signaled by HID_User
157 */
158void GetIPCHandles(Service::Interface* self) {
159 u32* cmd_buff = Service::GetCommandBuffer();
160
161 cmd_buff[1] = 0; // No error
162 cmd_buff[3] = shared_mem;
163 cmd_buff[4] = event_pad_or_touch_1;
164 cmd_buff[5] = event_pad_or_touch_2;
165 cmd_buff[6] = event_accelerometer;
166 cmd_buff[7] = event_gyroscope;
167 cmd_buff[8] = event_debug_pad;
168
169 DEBUG_LOG(KERNEL, "called");
170}
171
172const Interface::FunctionInfo FunctionTable[] = {
173 {0x000A0000, GetIPCHandles, "GetIPCHandles"},
174 {0x000B0000, nullptr, "StartAnalogStickCalibration"},
175 {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
176 {0x00110000, nullptr, "EnableAccelerometer"},
177 {0x00120000, nullptr, "DisableAccelerometer"},
178 {0x00130000, nullptr, "EnableGyroscopeLow"},
179 {0x00140000, nullptr, "DisableGyroscopeLow"},
180 {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"},
181 {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"},
182 {0x00170000, nullptr, "GetSoundVolume"},
183};
184
185
186////////////////////////////////////////////////////////////////////////////////////////////////////
187// Interface class
188
189Interface::Interface() {
190 shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object
191
192 // Create event handles
193 event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch1");
194 event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch2");
195 event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventAccelerometer");
196 event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope");
197 event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventDebugPad");
198
199 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
200}
201
202Interface::~Interface() {
203}
204
205} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8#include "common/bit_field.h"
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11// Namespace HID_User
12
13// This service is used for interfacing to physical user controls.
14// Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad.
15
16namespace HID_User {
17
18/**
19 * Structure of a Pad controller state.
20 */
21struct PadState {
22 union {
23 u32 hex;
24
25 BitField<0, 1, u32> a;
26 BitField<1, 1, u32> b;
27 BitField<2, 1, u32> select;
28 BitField<3, 1, u32> start;
29 BitField<4, 1, u32> right;
30 BitField<5, 1, u32> left;
31 BitField<6, 1, u32> up;
32 BitField<7, 1, u32> down;
33 BitField<8, 1, u32> r;
34 BitField<9, 1, u32> l;
35 BitField<10, 1, u32> x;
36 BitField<11, 1, u32> y;
37
38 BitField<28, 1, u32> circle_right;
39 BitField<29, 1, u32> circle_left;
40 BitField<30, 1, u32> circle_up;
41 BitField<31, 1, u32> circle_down;
42 };
43};
44
45/**
46 * Structure of a single entry in the PadData's Pad state history array.
47 */
48struct PadDataEntry {
49 PadState current_state;
50 PadState delta_additions;
51 PadState delta_removals;
52
53 s16 circle_pad_x;
54 s16 circle_pad_y;
55};
56
57/**
58 * Structure of all data related to the 3DS Pad.
59 */
60struct PadData {
61 s64 index_reset_ticks;
62 s64 index_reset_ticks_previous;
63 u32 index; // the index of the last updated Pad state history element
64
65 u32 pad1;
66 u32 pad2;
67
68 PadState current_state; // same as entries[index].current_state
69 u32 raw_circle_pad_data;
70
71 u32 pad3;
72
73 std::array<PadDataEntry, 8> entries; // Pad state history
74};
75
76// Pre-defined PadStates for single button presses
77const PadState PAD_NONE = {{0}};
78const PadState PAD_A = {{1u << 0}};
79const PadState PAD_B = {{1u << 1}};
80const PadState PAD_SELECT = {{1u << 2}};
81const PadState PAD_START = {{1u << 3}};
82const PadState PAD_RIGHT = {{1u << 4}};
83const PadState PAD_LEFT = {{1u << 5}};
84const PadState PAD_UP = {{1u << 6}};
85const PadState PAD_DOWN = {{1u << 7}};
86const PadState PAD_R = {{1u << 8}};
87const PadState PAD_L = {{1u << 9}};
88const PadState PAD_X = {{1u << 10}};
89const PadState PAD_Y = {{1u << 11}};
90const PadState PAD_CIRCLE_RIGHT = {{1u << 28}};
91const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
92const PadState PAD_CIRCLE_UP = {{1u << 30}};
93const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
94
95// Methods for updating the HID module's state
96void PadButtonPress(PadState pad_state);
97void PadButtonRelease(PadState pad_state);
98void PadUpdateComplete();
99
100/**
101 * HID service interface.
102 */
103class Interface : public Service::Interface {
104public:
105
106 Interface();
107
108 ~Interface();
109
110 /**
111 * Gets the string port name used by CTROS for the service
112 * @return Port name of service
113 */
114 std::string GetPortName() const override {
115 return "hid:USER";
116 }
117
118};
119
120} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/mic_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace MIC_U
11
12namespace MIC_U {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010042, nullptr, "MapSharedMem"},
16 {0x00020000, nullptr, "UnmapSharedMem"},
17 {0x00030140, nullptr, "Initialize"},
18 {0x00040040, nullptr, "AdjustSampling"},
19 {0x00050000, nullptr, "StopSampling"},
20 {0x00060000, nullptr, "IsSampling"},
21 {0x00070000, nullptr, "GetEventHandle"},
22 {0x00080040, nullptr, "SetControl"},
23 {0x00090000, nullptr, "GetControl"},
24 {0x000A0040, nullptr, "SetBias"},
25 {0x000B0000, nullptr, "GetBias"},
26 {0x000C0042, nullptr, "size"},
27 {0x000D0040, nullptr, "SetClamp"},
28 {0x000E0000, nullptr, "GetClamp"},
29 {0x000F0040, nullptr, "unknown_input1"},
30 {0x00100040, nullptr, "unknown_input2"},
31};
32
33////////////////////////////////////////////////////////////////////////////////////////////////////
34// Interface class
35
36Interface::Interface() {
37 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
38}
39
40Interface::~Interface() {
41}
42
43} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace MIC_U
11
12// mic service
13
14namespace MIC_U {
15
16class Interface : public Service::Interface {
17public:
18 Interface();
19 ~Interface();
20 /**
21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service
23 */
24 std::string GetPortName() const {
25 return "mic:u";
26 }
27};
28
29} // 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 @@
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h"
6
7#include "core/hle/hle.h" 5#include "core/hle/hle.h"
8#include "core/hle/service/ndm.h" 6#include "ndm_u.h"
9 7
10//////////////////////////////////////////////////////////////////////////////////////////////////// 8////////////////////////////////////////////////////////////////////////////////////////////////////
11// Namespace NDM_U 9// 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:
24 * Gets the string port name used by CTROS for the service 24 * Gets the string port name used by CTROS for the service
25 * @return Port name of service 25 * @return Port name of service
26 */ 26 */
27 std::string GetPortName() const { 27 std::string GetPortName() const override {
28 return "ndm:u"; 28 return "ndm:u";
29 } 29 }
30 30
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/nwm_uds.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NWM_UDS
11
12namespace NWM_UDS {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00030000, nullptr, "Shutdown"},
16 {0x000F0404, nullptr, "RecvBeaconBroadcastData"},
17 {0x00100042, nullptr, "SetBeaconAdditionalData"},
18 {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
19 {0x001B0302, nullptr, "Initialize"},
20 {0x001D0044, nullptr, "BeginHostingNetwork"},
21 {0x001E0084, nullptr, "ConnectToNetwork"},
22 {0x001F0006, nullptr, "DecryptBeaconData"},
23};
24
25////////////////////////////////////////////////////////////////////////////////////////////////////
26// Interface class
27
28Interface::Interface() {
29 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
30}
31
32Interface::~Interface() {
33}
34
35} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NWM_UDS
11
12// local-WLAN service
13
14namespace NWM_UDS {
15
16class Interface : public Service::Interface {
17public:
18 Interface();
19 ~Interface();
20 /**
21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service
23 */
24 std::string GetPortName() const {
25 return "nwm:UDS";
26 }
27};
28
29} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/ptm_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace PTM_U
11
12namespace PTM_U {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010002, nullptr, "RegisterAlarmClient"},
16 {0x00020080, nullptr, "SetRtcAlarm"},
17 {0x00030000, nullptr, "GetRtcAlarm"},
18 {0x00040000, nullptr, "CancelRtcAlarm"},
19 {0x00050000, nullptr, "GetAdapterState"},
20 {0x00060000, nullptr, "GetShellState "},
21 {0x00070000, nullptr, "GetBatteryLevel"},
22 {0x00080000, nullptr, "GetBatteryChargeState"},
23 {0x00090000, nullptr, "GetPedometerState"},
24 {0x000A0042, nullptr, "GetStepHistoryEntry"},
25 {0x000B00C2, nullptr, "GetStepHistory "},
26 {0x000C0000, nullptr, "GetTotalStepCount "},
27 {0x000D0040, nullptr, "SetPedometerRecordingMode"},
28 {0x000E0000, nullptr, "GetPedometerRecordingMode"},
29 {0x000F0084, nullptr, "GetStepHistoryAll"},
30};
31
32////////////////////////////////////////////////////////////////////////////////////////////////////
33// Interface class
34
35Interface::Interface() {
36 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
37}
38
39Interface::~Interface() {
40}
41
42} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace PTM_U
11
12// ptm service
13
14namespace PTM_U {
15
16class Interface : public Service::Interface {
17public:
18 Interface();
19 ~Interface();
20 /**
21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service
23 */
24 std::string GetPortName() const {
25 return "ptm:u";
26 }
27};
28
29} // 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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
6#include "common/log.h"
7#include "common/string_util.h" 6#include "common/string_util.h"
8 7
9#include "core/hle/hle.h"
10
11#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
12#include "core/hle/service/apt.h" 9#include "core/hle/service/ac_u.h"
13#include "core/hle/service/fs.h" 10#include "core/hle/service/apt_u.h"
14#include "core/hle/service/gsp.h" 11#include "core/hle/service/cfg_u.h"
15#include "core/hle/service/hid.h" 12#include "core/hle/service/dsp_dsp.h"
16#include "core/hle/service/ndm.h" 13#include "core/hle/service/err_f.h"
14#include "core/hle/service/fs_user.h"
15#include "core/hle/service/frd_u.h"
16#include "core/hle/service/gsp_gpu.h"
17#include "core/hle/service/hid_user.h"
18#include "core/hle/service/mic_u.h"
19#include "core/hle/service/ndm_u.h"
20#include "core/hle/service/nwm_uds.h"
21#include "core/hle/service/ptm_u.h"
22#include "core/hle/service/soc_u.h"
17#include "core/hle/service/srv.h" 23#include "core/hle/service/srv.h"
18 24#include "core/hle/service/ssl_c.h"
19#include "core/hle/kernel/kernel.h"
20 25
21namespace Service { 26namespace Service {
22 27
@@ -71,11 +76,21 @@ void Init() {
71 g_manager = new Manager; 76 g_manager = new Manager;
72 77
73 g_manager->AddService(new SRV::Interface); 78 g_manager->AddService(new SRV::Interface);
79 g_manager->AddService(new AC_U::Interface);
74 g_manager->AddService(new APT_U::Interface); 80 g_manager->AddService(new APT_U::Interface);
81 g_manager->AddService(new CFG_U::Interface);
82 g_manager->AddService(new DSP_DSP::Interface);
83 g_manager->AddService(new ERR_F::Interface);
84 g_manager->AddService(new FRD_U::Interface);
75 g_manager->AddService(new FS_User::Interface); 85 g_manager->AddService(new FS_User::Interface);
76 g_manager->AddService(new GSP_GPU::Interface); 86 g_manager->AddService(new GSP_GPU::Interface);
77 g_manager->AddService(new HID_User::Interface); 87 g_manager->AddService(new HID_User::Interface);
88 g_manager->AddService(new MIC_U::Interface);
78 g_manager->AddService(new NDM_U::Interface); 89 g_manager->AddService(new NDM_U::Interface);
90 g_manager->AddService(new NWM_UDS::Interface);
91 g_manager->AddService(new PTM_U::Interface);
92 g_manager->AddService(new SOC_U::Interface);
93 g_manager->AddService(new SSL_C::Interface);
79 94
80 NOTICE_LOG(HLE, "initialized OK"); 95 NOTICE_LOG(HLE, "initialized OK");
81} 96}
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 {
39 friend class Manager; 39 friend class Manager;
40public: 40public:
41 41
42 std::string GetName() const { return GetPortName(); } 42 std::string GetName() const override { return GetPortName(); }
43 std::string GetTypeName() const { return GetPortName(); } 43 std::string GetTypeName() const override { return GetPortName(); }
44 44
45 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } 45 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; }
46 Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } 46 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Service; }
47 47
48 typedef void (*Function)(Interface*); 48 typedef void (*Function)(Interface*);
49 49
@@ -80,7 +80,7 @@ public:
80 * @param wait Boolean wait set if current thread should wait as a result of sync operation 80 * @param wait Boolean wait set if current thread should wait as a result of sync operation
81 * @return Result of operation, 0 on success, otherwise error code 81 * @return Result of operation, 0 on success, otherwise error code
82 */ 82 */
83 Result SyncRequest(bool* wait) { 83 Result SyncRequest(bool* wait) override {
84 u32* cmd_buff = GetCommandBuffer(); 84 u32* cmd_buff = GetCommandBuffer();
85 auto itr = m_functions.find(cmd_buff[0]); 85 auto itr = m_functions.find(cmd_buff[0]);
86 86
@@ -113,7 +113,7 @@ public:
113 * @param wait Boolean wait set if current thread should wait as a result of sync operation 113 * @param wait Boolean wait set if current thread should wait as a result of sync operation
114 * @return Result of operation, 0 on success, otherwise error code 114 * @return Result of operation, 0 on success, otherwise error code
115 */ 115 */
116 Result WaitSynchronization(bool* wait) { 116 Result WaitSynchronization(bool* wait) override {
117 // TODO(bunnei): ImplementMe 117 // TODO(bunnei): ImplementMe
118 ERROR_LOG(OSHLE, "unimplemented function"); 118 ERROR_LOG(OSHLE, "unimplemented function");
119 return 0; 119 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/soc_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace SOC_U
11
12namespace SOC_U {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010044, nullptr, "InitializeSockets"},
16 {0x000200C2, nullptr, "socket"},
17 {0x00030082, nullptr, "listen"},
18 {0x00040082, nullptr, "accept"},
19 {0x00050084, nullptr, "bind"},
20 {0x00060084, nullptr, "connect"},
21 {0x00070104, nullptr, "recvfrom_other"},
22 {0x00080102, nullptr, "recvfrom"},
23 {0x00090106, nullptr, "sendto_other"},
24 {0x000A0106, nullptr, "sendto"},
25 {0x000B0042, nullptr, "close"},
26 {0x000C0082, nullptr, "shutdown"},
27 {0x000D0082, nullptr, "gethostbyname"},
28 {0x000E00C2, nullptr, "gethostbyaddr"},
29 {0x000F0106, nullptr, "unknown_resolve_ip"},
30 {0x00110102, nullptr, "getsockopt"},
31 {0x00120104, nullptr, "setsockopt"},
32 {0x001300C2, nullptr, "fcntl"},
33 {0x00140084, nullptr, "poll"},
34 {0x00150042, nullptr, "sockatmark"},
35 {0x00160000, nullptr, "gethostid"},
36 {0x00170082, nullptr, "getsockname"},
37 {0x00180082, nullptr, "getpeername"},
38 {0x00190000, nullptr, "ShutdownSockets"},
39 {0x001A00C0, nullptr, "GetNetworkOpt"},
40 {0x001B0040, nullptr, "ICMPSocket"},
41 {0x001C0104, nullptr, "ICMPPing"},
42 {0x001D0040, nullptr, "ICMPCancel"},
43 {0x001E0040, nullptr, "ICMPClose"},
44 {0x001F0040, nullptr, "GetResolverInfo"},
45 {0x00210002, nullptr, "CloseSockets"},
46};
47
48////////////////////////////////////////////////////////////////////////////////////////////////////
49// Interface class
50
51Interface::Interface() {
52 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
53}
54
55Interface::~Interface() {
56}
57
58} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace SOC_U
11
12namespace SOC_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const {
23 return "soc:U";
24 }
25};
26
27} // 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 @@
4 4
5#include "core/hle/hle.h" 5#include "core/hle/hle.h"
6#include "core/hle/service/srv.h" 6#include "core/hle/service/srv.h"
7#include "core/hle/service/service.h"
8#include "core/hle/kernel/event.h" 7#include "core/hle/kernel/event.h"
9 8
10//////////////////////////////////////////////////////////////////////////////////////////////////// 9////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -58,6 +57,8 @@ const Interface::FunctionInfo FunctionTable[] = {
58 {0x00030100, nullptr, "RegisterService"}, 57 {0x00030100, nullptr, "RegisterService"},
59 {0x000400C0, nullptr, "UnregisterService"}, 58 {0x000400C0, nullptr, "UnregisterService"},
60 {0x00050100, GetServiceHandle, "GetServiceHandle"}, 59 {0x00050100, GetServiceHandle, "GetServiceHandle"},
60 {0x000B0000, nullptr, "ReceiveNotification"},
61 {0x000C0080, nullptr, "PublishToSubscriber"}
61}; 62};
62 63
63//////////////////////////////////////////////////////////////////////////////////////////////////// 64////////////////////////////////////////////////////////////////////////////////////////////////////
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:
22 * Gets the string name used by CTROS for the service 22 * Gets the string name used by CTROS for the service
23 * @return Port name of service 23 * @return Port name of service
24 */ 24 */
25 std::string GetPortName() const { 25 std::string GetPortName() const override {
26 return "srv:"; 26 return "srv:";
27 } 27 }
28 28
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/ssl_c.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace SSL_C
11
12namespace SSL_C {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x000200C2, nullptr, "CreateContext"},
16 {0x00050082, nullptr, "AddTrustedRootCA"},
17 {0x00150082, nullptr, "Read"},
18 {0x00170082, nullptr, "Write"},
19};
20
21////////////////////////////////////////////////////////////////////////////////////////////////////
22// Interface class
23
24Interface::Interface() {
25 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
26}
27
28Interface::~Interface() {
29}
30
31} // 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace SSL_C
11
12namespace SSL_C {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const {
23 return "ssl:C";
24 }
25};
26
27} // 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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6#include <string>
7 6
8#include "common/string_util.h" 7#include "common/string_util.h"
9#include "common/symbols.h" 8#include "common/symbols.h"
@@ -12,13 +11,11 @@
12 11
13#include "core/hle/kernel/address_arbiter.h" 12#include "core/hle/kernel/address_arbiter.h"
14#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/event.h"
15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/mutex.h" 14#include "core/hle/kernel/mutex.h"
17#include "core/hle/kernel/shared_memory.h" 15#include "core/hle/kernel/shared_memory.h"
18#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
19 17
20#include "core/hle/function_wrappers.h" 18#include "core/hle/function_wrappers.h"
21#include "core/hle/svc.h"
22#include "core/hle/service/service.h" 19#include "core/hle/service/service.h"
23 20
24//////////////////////////////////////////////////////////////////////////////////////////////////// 21////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -118,7 +115,7 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
118 115
119 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); 116 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
120 117
121 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName().c_str(), 118 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(),
122 object->GetName().c_str(), nano_seconds); 119 object->GetName().c_str(), nano_seconds);
123 120
124 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); 121 _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
141 bool unlock_all = true; 138 bool unlock_all = true;
142 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated 139 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
143 140
144 DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d", 141 DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld",
145 handle_count, (wait_all ? "true" : "false"), nano_seconds); 142 handle_count, (wait_all ? "true" : "false"), nano_seconds);
146 143
147 // Iterate through each handle, synchronize kernel object 144 // 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
221 TSymbol symbol = Symbols::GetSymbol(entry_point); 218 TSymbol symbol = Symbols::GetSymbol(entry_point);
222 name = symbol.name; 219 name = symbol.name;
223 } else { 220 } else {
224 name = StringFromFormat("unknown-%08x", entry_point); 221 name = Common::StringFromFormat("unknown-%08x", entry_point);
225 } 222 }
226 223
227 Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id, 224 Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id,
@@ -327,7 +324,7 @@ Result ClearEvent(Handle evt) {
327 324
328/// Sleep the current thread 325/// Sleep the current thread
329void SleepThread(s64 nanoseconds) { 326void SleepThread(s64 nanoseconds) {
330 DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds); 327 DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds);
331} 328}
332 329
333/// This returns the total CPU ticks elapsed since the CPU was powered-on 330/// 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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/log.h"
7 6
7#include "core/settings.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/mem_map.h" 9#include "core/mem_map.h"
10 10
11#include "core/hle/hle.h" 11#include "core/hle/hle.h"
12#include "core/hle/kernel/thread.h" 12#include "core/hle/service/gsp_gpu.h"
13#include "core/hle/service/gsp.h"
14 13
15#include "core/hw/gpu.h" 14#include "core/hw/gpu.h"
16 15
@@ -26,14 +25,17 @@ u32 g_cur_line = 0; ///< Current vertical screen line
26u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line 25u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
27u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame 26u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame
28 27
28static u32 kFrameCycles = 0; ///< 268MHz / 60 frames per second
29static u32 kFrameTicks = 0; ///< Approximate number of instructions/frame
30
29template <typename T> 31template <typename T>
30inline void Read(T &var, const u32 raw_addr) { 32inline void Read(T &var, const u32 raw_addr) {
31 u32 addr = raw_addr - 0x1EF00000; 33 u32 addr = raw_addr - 0x1EF00000;
32 int index = addr / 4; 34 u32 index = addr / 4;
33 35
34 // Reads other than u32 are untested, so I'd rather have them abort than silently fail 36 // Reads other than u32 are untested, so I'd rather have them abort than silently fail
35 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { 37 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) {
36 ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); 38 ERROR_LOG(GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
37 return; 39 return;
38 } 40 }
39 41
@@ -43,15 +45,15 @@ inline void Read(T &var, const u32 raw_addr) {
43template <typename T> 45template <typename T>
44inline void Write(u32 addr, const T data) { 46inline void Write(u32 addr, const T data) {
45 addr -= 0x1EF00000; 47 addr -= 0x1EF00000;
46 int index = addr / 4; 48 u32 index = addr / 4;
47 49
48 // Writes other than u32 are untested, so I'd rather have them abort than silently fail 50 // Writes other than u32 are untested, so I'd rather have them abort than silently fail
49 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { 51 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) {
50 ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 52 ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
51 return; 53 return;
52 } 54 }
53 55
54 g_regs[index] = data; 56 g_regs[index] = static_cast<u32>(data);
55 57
56 switch (index) { 58 switch (index) {
57 59
@@ -83,15 +85,15 @@ inline void Write(u32 addr, const T data) {
83 u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); 85 u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress()));
84 u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); 86 u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress()));
85 87
86 for (int y = 0; y < config.output_height; ++y) { 88 for (u32 y = 0; y < config.output_height; ++y) {
87 // TODO: Why does the register seem to hold twice the framebuffer width? 89 // TODO: Why does the register seem to hold twice the framebuffer width?
88 for (int x = 0; x < config.output_width; ++x) { 90 for (u32 x = 0; x < config.output_width; ++x) {
89 struct { 91 struct {
90 int r, g, b, a; 92 int r, g, b, a;
91 } source_color = { 0, 0, 0, 0 }; 93 } source_color = { 0, 0, 0, 0 };
92 94
93 switch (config.input_format) { 95 switch (config.input_format) {
94 case Regs::FramebufferFormat::RGBA8: 96 case Regs::PixelFormat::RGBA8:
95 { 97 {
96 // TODO: Most likely got the component order messed up. 98 // TODO: Most likely got the component order messed up.
97 u8* srcptr = source_pointer + x * 4 + y * config.input_width * 4; 99 u8* srcptr = source_pointer + x * 4 + y * config.input_width * 4;
@@ -108,7 +110,7 @@ inline void Write(u32 addr, const T data) {
108 } 110 }
109 111
110 switch (config.output_format) { 112 switch (config.output_format) {
111 /*case Regs::FramebufferFormat::RGBA8: 113 /*case Regs::PixelFormat::RGBA8:
112 { 114 {
113 // TODO: Untested 115 // TODO: Untested
114 u8* dstptr = (u32*)(dest_pointer + x * 4 + y * config.output_width * 4); 116 u8* dstptr = (u32*)(dest_pointer + x * 4 + y * config.output_width * 4);
@@ -119,7 +121,7 @@ inline void Write(u32 addr, const T data) {
119 break; 121 break;
120 }*/ 122 }*/
121 123
122 case Regs::FramebufferFormat::RGB8: 124 case Regs::PixelFormat::RGB8:
123 { 125 {
124 // TODO: Most likely got the component order messed up. 126 // TODO: Most likely got the component order messed up.
125 u8* dstptr = dest_pointer + x * 3 + y * config.output_width * 3; 127 u8* dstptr = dest_pointer + x * 3 + y * config.output_width * 3;
@@ -136,10 +138,10 @@ inline void Write(u32 addr, const T data) {
136 } 138 }
137 } 139 }
138 140
139 DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%dx%d)-> 0x%08x(%dx%d), dst format %x", 141 DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x",
140 config.output_height * config.output_width * 4, 142 config.output_height * config.output_width * 4,
141 config.GetPhysicalInputAddress(), (int)config.input_width, (int)config.input_height, 143 config.GetPhysicalInputAddress(), config.input_width, config.input_height,
142 config.GetPhysicalOutputAddress(), (int)config.output_width, (int)config.output_height, 144 config.GetPhysicalOutputAddress(), config.output_width, config.output_height,
143 config.output_format.Value()); 145 config.output_format.Value());
144 } 146 }
145 break; 147 break;
@@ -216,6 +218,9 @@ void Update() {
216 218
217/// Initialize hardware 219/// Initialize hardware
218void Init() { 220void Init() {
221 kFrameCycles = 268123480 / Settings::values.gpu_refresh_rate;
222 kFrameTicks = kFrameCycles / 3;
223
219 g_cur_line = 0; 224 g_cur_line = 0;
220 g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks(); 225 g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks();
221 226
@@ -238,13 +243,13 @@ void Init() {
238 framebuffer_top.width = 240; 243 framebuffer_top.width = 240;
239 framebuffer_top.height = 400; 244 framebuffer_top.height = 400;
240 framebuffer_top.stride = 3 * 240; 245 framebuffer_top.stride = 3 * 240;
241 framebuffer_top.color_format = Regs::FramebufferFormat::RGB8; 246 framebuffer_top.color_format = Regs::PixelFormat::RGB8;
242 framebuffer_top.active_fb = 0; 247 framebuffer_top.active_fb = 0;
243 248
244 framebuffer_sub.width = 240; 249 framebuffer_sub.width = 240;
245 framebuffer_sub.height = 320; 250 framebuffer_sub.height = 320;
246 framebuffer_sub.stride = 3 * 240; 251 framebuffer_sub.stride = 3 * 240;
247 framebuffer_sub.color_format = Regs::FramebufferFormat::RGB8; 252 framebuffer_sub.color_format = Regs::PixelFormat::RGB8;
248 framebuffer_sub.active_fb = 0; 253 framebuffer_sub.active_fb = 0;
249 254
250 NOTICE_LOG(GPU, "initialized OK"); 255 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 @@
11 11
12namespace GPU { 12namespace GPU {
13 13
14static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
15static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
16
17// Returns index corresponding to the Regs member labeled by field_name 14// Returns index corresponding to the Regs member labeled by field_name
18// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions 15// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
19// when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])). 16// when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])).
@@ -56,7 +53,7 @@ struct Regs {
56 "Structure size and register block length don't match") 53 "Structure size and register block length don't match")
57#endif 54#endif
58 55
59 enum class FramebufferFormat : u32 { 56 enum class PixelFormat : u32 {
60 RGBA8 = 0, 57 RGBA8 = 0,
61 RGB8 = 1, 58 RGB8 = 1,
62 RGB565 = 2, 59 RGB565 = 2,
@@ -84,9 +81,7 @@ struct Regs {
84 81
85 INSERT_PADDING_WORDS(0x10b); 82 INSERT_PADDING_WORDS(0x10b);
86 83
87 struct { 84 struct FramebufferConfig {
88 using Format = Regs::FramebufferFormat;
89
90 union { 85 union {
91 u32 size; 86 u32 size;
92 87
@@ -102,7 +97,7 @@ struct Regs {
102 union { 97 union {
103 u32 format; 98 u32 format;
104 99
105 BitField< 0, 3, Format> color_format; 100 BitField< 0, 3, PixelFormat> color_format;
106 }; 101 };
107 102
108 INSERT_PADDING_WORDS(0x1); 103 INSERT_PADDING_WORDS(0x1);
@@ -130,8 +125,6 @@ struct Regs {
130 INSERT_PADDING_WORDS(0x169); 125 INSERT_PADDING_WORDS(0x169);
131 126
132 struct { 127 struct {
133 using Format = Regs::FramebufferFormat;
134
135 u32 input_address; 128 u32 input_address;
136 u32 output_address; 129 u32 output_address;
137 130
@@ -161,8 +154,8 @@ struct Regs {
161 u32 flags; 154 u32 flags;
162 155
163 BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true 156 BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true
164 BitField< 8, 3, Format> input_format; 157 BitField< 8, 3, PixelFormat> input_format;
165 BitField<12, 3, Format> output_format; 158 BitField<12, 3, PixelFormat> output_format;
166 BitField<16, 1, u32> output_tiled; // stores output in a tiled format 159 BitField<16, 1, u32> output_tiled; // stores output in a tiled format
167 }; 160 };
168 161
@@ -201,7 +194,7 @@ struct Regs {
201#undef INSERT_PADDING_WORDS_HELPER2 194#undef INSERT_PADDING_WORDS_HELPER2
202#undef INSERT_PADDING_WORDS 195#undef INSERT_PADDING_WORDS
203 196
204 static inline int NumIds() { 197 static inline size_t NumIds() {
205 return sizeof(Regs) / sizeof(u32); 198 return sizeof(Regs) / sizeof(u32);
206 } 199 }
207 200
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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/log.h"
7 6
8#include "core/hw/hw.h" 7#include "core/hw/hw.h"
9#include "core/hw/gpu.h" 8#include "core/hw/gpu.h"
@@ -51,7 +50,7 @@ inline void Read(T &var, const u32 addr) {
51 break; 50 break;
52 51
53 default: 52 default:
54 ERROR_LOG(HW, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); 53 ERROR_LOG(HW, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
55 } 54 }
56} 55}
57 56
@@ -69,7 +68,7 @@ inline void Write(u32 addr, const T data) {
69 break; 68 break;
70 69
71 default: 70 default:
72 ERROR_LOG(HW, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 71 ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
73 } 72 }
74} 73}
75 74
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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/log.h"
7 6
8#include "core/hw/ndma.h" 7#include "core/hw/ndma.h"
9 8
@@ -11,12 +10,12 @@ namespace NDMA {
11 10
12template <typename T> 11template <typename T>
13inline void Read(T &var, const u32 addr) { 12inline void Read(T &var, const u32 addr) {
14 ERROR_LOG(NDMA, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); 13 ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
15} 14}
16 15
17template <typename T> 16template <typename T>
18inline void Write(u32 addr, const T data) { 17inline void Write(u32 addr, const T data) {
19 ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 18 ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
20} 19}
21 20
22// Explicitly instantiate template functions because we aren't defining this in the header: 21// 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() {
351 if (is_loaded) 351 if (is_loaded)
352 return ResultStatus::ErrorAlreadyLoaded; 352 return ResultStatus::ErrorAlreadyLoaded;
353 353
354 File::IOFile file(filename, "rb"); 354 FileUtil::IOFile file(filename, "rb");
355 355
356 if (file.IsOpen()) { 356 if (file.IsOpen()) {
357 u32 size = (u32)file.GetSize(); 357 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 @@
5#include <memory> 5#include <memory>
6 6
7#include "core/file_sys/archive_romfs.h" 7#include "core/file_sys/archive_romfs.h"
8#include "core/loader/loader.h"
9#include "core/loader/elf.h" 8#include "core/loader/elf.h"
10#include "core/loader/ncch.h" 9#include "core/loader/ncch.h"
11#include "core/hle/kernel/archive.h" 10#include "core/hle/kernel/archive.h"
@@ -26,22 +25,23 @@ FileType IdentifyFile(const std::string &filename) {
26 ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); 25 ERROR_LOG(LOADER, "invalid filename %s", filename.c_str());
27 return FileType::Error; 26 return FileType::Error;
28 } 27 }
29 std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : "";
30 28
31 if (!strcasecmp(extension.c_str(), ".elf")) { 29 size_t extension_loc = filename.find_last_of('.');
32 return FileType::ELF; // TODO(bunnei): Do some filetype checking :p 30 if (extension_loc == std::string::npos)
33 } 31 return FileType::Unknown;
34 else if (!strcasecmp(extension.c_str(), ".axf")) { 32 std::string extension = Common::ToLower(filename.substr(extension_loc));
35 return FileType::ELF; // TODO(bunnei): Do some filetype checking :p 33
36 } 34 // TODO(bunnei): Do actual filetype checking instead of naively checking the extension
37 else if (!strcasecmp(extension.c_str(), ".cxi")) { 35 if (extension == ".elf") {
38 return FileType::CXI; // TODO(bunnei): Do some filetype checking :p 36 return FileType::ELF;
39 } 37 } else if (extension == ".axf") {
40 else if (!strcasecmp(extension.c_str(), ".cci")) { 38 return FileType::ELF;
41 return FileType::CCI; // TODO(bunnei): Do some filetype checking :p 39 } else if (extension == ".cxi") {
42 } 40 return FileType::CXI;
43 else if (!strcasecmp(extension.c_str(), ".bin")) { 41 } else if (extension == ".cci") {
44 return FileType::BIN; // TODO(bunnei): Do some filetype checking :p 42 return FileType::CCI;
43 } else if (extension == ".bin") {
44 return FileType::BIN;
45 } 45 }
46 return FileType::Unknown; 46 return FileType::Unknown;
47} 47}
@@ -78,7 +78,7 @@ ResultStatus LoadFile(const std::string& filename) {
78 { 78 {
79 INFO_LOG(LOADER, "Loading BIN file %s...", filename.c_str()); 79 INFO_LOG(LOADER, "Loading BIN file %s...", filename.c_str());
80 80
81 File::IOFile file(filename, "rb"); 81 FileUtil::IOFile file(filename, "rb");
82 82
83 if (file.IsOpen()) { 83 if (file.IsOpen()) {
84 file.ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), (size_t)file.GetSize()); 84 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 {
138 */ 138 */
139ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { 139ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const {
140 // Iterate through the ExeFs archive until we find the .code file... 140 // Iterate through the ExeFs archive until we find the .code file...
141 File::IOFile file(filename, "rb"); 141 FileUtil::IOFile file(filename, "rb");
142 if (file.IsOpen()) { 142 if (file.IsOpen()) {
143 for (int i = 0; i < kMaxSections; i++) { 143 for (int i = 0; i < kMaxSections; i++) {
144 // Load the specified section... 144 // Load the specified section...
@@ -199,7 +199,7 @@ ResultStatus AppLoader_NCCH::Load() {
199 if (is_loaded) 199 if (is_loaded)
200 return ResultStatus::ErrorAlreadyLoaded; 200 return ResultStatus::ErrorAlreadyLoaded;
201 201
202 File::IOFile file(filename, "rb"); 202 FileUtil::IOFile file(filename, "rb");
203 if (file.IsOpen()) { 203 if (file.IsOpen()) {
204 file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); 204 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
205 205
@@ -290,7 +290,7 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const {
290 * @return ResultStatus result of function 290 * @return ResultStatus result of function
291 */ 291 */
292ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { 292ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
293 File::IOFile file(filename, "rb"); 293 FileUtil::IOFile file(filename, "rb");
294 if (file.IsOpen()) { 294 if (file.IsOpen()) {
295 // Check if the NCCH has a RomFS... 295 // Check if the NCCH has a RomFS...
296 if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) { 296 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 @@
6#include "common/mem_arena.h" 6#include "common/mem_arena.h"
7 7
8#include "core/mem_map.h" 8#include "core/mem_map.h"
9#include "core/core.h"
10 9
11//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
12 11
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 @@
8 8
9#include "core/mem_map.h" 9#include "core/mem_map.h"
10#include "core/hw/hw.h" 10#include "core/hw/hw.h"
11#include "hle/hle.h"
12#include "hle/config_mem.h" 11#include "hle/config_mem.h"
13 12
14namespace Memory { 13namespace Memory {
@@ -288,7 +287,7 @@ void Write64(const VAddr addr, const u64 data) {
288} 287}
289 288
290void WriteBlock(const VAddr addr, const u8* data, const size_t size) { 289void WriteBlock(const VAddr addr, const u8* data, const size_t size) {
291 int offset = 0; 290 u32 offset = 0;
292 while (offset < (size & ~3)) { 291 while (offset < (size & ~3)) {
293 Write32(addr + offset, *(u32*)&data[offset]); 292 Write32(addr + offset, *(u32*)&data[offset]);
294 offset += 4; 293 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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "settings.h"
6
7namespace Settings {
8
9Values values = {};
10
11}
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Settings {
8
9struct Values {
10 // Controls
11 int pad_a_key;
12 int pad_b_key;
13 int pad_x_key;
14 int pad_y_key;
15 int pad_l_key;
16 int pad_r_key;
17 int pad_start_key;
18 int pad_select_key;
19 int pad_home_key;
20 int pad_dup_key;
21 int pad_ddown_key;
22 int pad_dleft_key;
23 int pad_dright_key;
24 int pad_sup_key;
25 int pad_sdown_key;
26 int pad_sleft_key;
27 int pad_sright_key;
28
29 // Core
30 int cpu_core;
31 int gpu_refresh_rate;
32
33 // Data Storage
34 bool use_virtual_sd;
35} extern values;
36
37}
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)
86 86
87 viewport.halfsize_x = float24::FromRawFloat24(registers.viewport_size_x); 87 viewport.halfsize_x = float24::FromRawFloat24(registers.viewport_size_x);
88 viewport.halfsize_y = float24::FromRawFloat24(registers.viewport_size_y); 88 viewport.halfsize_y = float24::FromRawFloat24(registers.viewport_size_y);
89 viewport.offset_x = float24::FromFloat32(registers.viewport_corner.x); 89 viewport.offset_x = float24::FromFloat32(static_cast<float>(registers.viewport_corner.x));
90 viewport.offset_y = float24::FromFloat32(registers.viewport_corner.y); 90 viewport.offset_y = float24::FromFloat32(static_cast<float>(registers.viewport_corner.y));
91 viewport.zscale = float24::FromRawFloat24(registers.viewport_depth_range); 91 viewport.zscale = float24::FromRawFloat24(registers.viewport_depth_range);
92 viewport.offset_z = float24::FromRawFloat24(registers.viewport_depth_far_plane); 92 viewport.offset_z = float24::FromRawFloat24(registers.viewport_depth_far_plane);
93 93
@@ -150,7 +150,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
150 InitScreenCoordinates(*(output_list[0])); 150 InitScreenCoordinates(*(output_list[0]));
151 InitScreenCoordinates(*(output_list[1])); 151 InitScreenCoordinates(*(output_list[1]));
152 152
153 for (int i = 0; i < output_list.size() - 2; i ++) { 153 for (size_t i = 0; i < output_list.size() - 2; i ++) {
154 OutputVertex& vtx0 = *(output_list[0]); 154 OutputVertex& vtx0 = *(output_list[0]);
155 OutputVertex& vtx1 = *(output_list[i+1]); 155 OutputVertex& vtx1 = *(output_list[i+1]);
156 OutputVertex& vtx2 = *(output_list[i+2]); 156 OutputVertex& vtx2 = *(output_list[i+2]);
@@ -158,8 +158,8 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
158 InitScreenCoordinates(vtx2); 158 InitScreenCoordinates(vtx2);
159 159
160 DEBUG_LOG(GPU, 160 DEBUG_LOG(GPU,
161 "Triangle %d/%d (%d buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), " 161 "Triangle %lu/%lu (%lu buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), "
162 "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " 162 "(%.3lu, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
163 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", 163 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)",
164 i,output_list.size(), buffer_vertices.size(), 164 i,output_list.size(), buffer_vertices.size(),
165 vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),output_list.size(), 165 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) {
63 for (int component = 0; component < loader_config.component_count; ++component) { 63 for (int component = 0; component < loader_config.component_count; ++component) {
64 u32 attribute_index = loader_config.GetComponent(component); 64 u32 attribute_index = loader_config.GetComponent(component);
65 vertex_attribute_sources[attribute_index] = load_address; 65 vertex_attribute_sources[attribute_index] = load_address;
66 vertex_attribute_strides[attribute_index] = loader_config.byte_count; 66 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
67 vertex_attribute_formats[attribute_index] = (u32)attribute_config.GetFormat(attribute_index); 67 vertex_attribute_formats[attribute_index] = static_cast<u32>(attribute_config.GetFormat(attribute_index));
68 vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index); 68 vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index);
69 vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index); 69 vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index);
70 load_address += attribute_config.GetStride(attribute_index); 70 load_address += attribute_config.GetStride(attribute_index);
@@ -83,9 +83,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
83 PrimitiveAssembler<VertexShader::OutputVertex> clipper_primitive_assembler(registers.triangle_topology.Value()); 83 PrimitiveAssembler<VertexShader::OutputVertex> clipper_primitive_assembler(registers.triangle_topology.Value());
84 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(registers.triangle_topology.Value()); 84 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(registers.triangle_topology.Value());
85 85
86 for (int index = 0; index < registers.num_vertices; ++index) 86 for (unsigned int index = 0; index < registers.num_vertices; ++index)
87 { 87 {
88 int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index; 88 unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index;
89 89
90 if (is_indexed) { 90 if (is_indexed) {
91 // TODO: Implement some sort of vertex cache! 91 // TODO: Implement some sort of vertex cache!
@@ -95,14 +95,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
95 VertexShader::InputVertex input; 95 VertexShader::InputVertex input;
96 96
97 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { 97 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) {
98 for (int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 98 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
99 const u8* srcdata = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]; 99 const u8* srcdata = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
100 const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata : 100 const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata :
101 (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata : 101 (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata :
102 (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata : 102 (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata :
103 *(float*)srcdata; 103 *(float*)srcdata;
104 input.attr[i][comp] = float24::FromFloat32(srcval); 104 input.attr[i][comp] = float24::FromFloat32(srcval);
105 DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08x + 0x%04x: %f", 105 DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
106 comp, i, vertex, index, 106 comp, i, vertex, index,
107 attribute_config.GetBaseAddress(), 107 attribute_config.GetBaseAddress(),
108 vertex_attribute_sources[i] - base_address, 108 vertex_attribute_sources[i] - base_address,
@@ -244,7 +244,7 @@ static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) {
244 WritePicaReg(header.cmd_id, *read_pointer, write_mask); 244 WritePicaReg(header.cmd_id, *read_pointer, write_mask);
245 read_pointer += 2; 245 read_pointer += 2;
246 246
247 for (int i = 1; i < 1+header.extra_data_length; ++i) { 247 for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) {
248 u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0); 248 u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0);
249 WritePicaReg(cmd, *read_pointer, write_mask); 249 WritePicaReg(cmd, *read_pointer, write_mask);
250 ++read_pointer; 250 ++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
203 } else { 203 } else {
204 it->component_mask = it->component_mask | component_mask; 204 it->component_mask = it->component_mask | component_mask;
205 } 205 }
206 } catch (const std::out_of_range& oor) { 206 } catch (const std::out_of_range& ) {
207 _dbg_assert_msg_(GPU, 0, "Unknown output attribute mapping"); 207 _dbg_assert_msg_(GPU, 0, "Unknown output attribute mapping");
208 ERROR_LOG(GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x", 208 ERROR_LOG(GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x",
209 (int)output_attributes[i].map_x.Value(), 209 (int)output_attributes[i].map_x.Value(),
@@ -235,7 +235,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
235 dvlp.swizzle_patterns_offset = write_offset - dvlp_offset; 235 dvlp.swizzle_patterns_offset = write_offset - dvlp_offset;
236 dvlp.swizzle_patterns_num_entries = swizzle_size; 236 dvlp.swizzle_patterns_num_entries = swizzle_size;
237 u32 dummy = 0; 237 u32 dummy = 0;
238 for (int i = 0; i < swizzle_size; ++i) { 238 for (unsigned int i = 0; i < swizzle_size; ++i) {
239 QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i])); 239 QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i]));
240 QueueForWriting((u8*)&dummy, sizeof(dummy)); 240 QueueForWriting((u8*)&dummy, sizeof(dummy));
241 } 241 }
@@ -278,7 +278,7 @@ void StartPicaTracing()
278 278
279bool IsPicaTracing() 279bool IsPicaTracing()
280{ 280{
281 return is_pica_tracing; 281 return is_pica_tracing != 0;
282} 282}
283 283
284void OnPicaRegWrite(u32 id, u32 value) 284void OnPicaRegWrite(u32 id, u32 value)
@@ -336,7 +336,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
336 png_infop info_ptr = nullptr; 336 png_infop info_ptr = nullptr;
337 337
338 // Open file for writing (binary mode) 338 // Open file for writing (binary mode)
339 File::IOFile fp(filename, "wb"); 339 FileUtil::IOFile fp(filename, "wb");
340 340
341 // Initialize write structure 341 // Initialize write structure
342 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 342 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)
428 using Operation = Pica::Regs::TevStageConfig::Operation; 428 using Operation = Pica::Regs::TevStageConfig::Operation;
429 429
430 std::string stage_info = "Tev setup:\n"; 430 std::string stage_info = "Tev setup:\n";
431 for (int index = 0; index < stages.size(); ++index) { 431 for (size_t index = 0; index < stages.size(); ++index) {
432 const auto& tev_stage = stages[index]; 432 const auto& tev_stage = stages[index];
433 433
434 const std::map<Source, std::string> source_map = { 434 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 @@
10 10
11#include "common/log.h" 11#include "common/log.h"
12 12
13#include "core/hle/service/gsp.h" 13#include "core/hle/service/gsp_gpu.h"
14 14
15#include "command_processor.h" 15#include "command_processor.h"
16#include "pica.h" 16#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 {
516 // Used for debugging purposes, so performance is not an issue here 516 // Used for debugging purposes, so performance is not an issue here
517 static std::string GetCommandName(int index) { 517 static std::string GetCommandName(int index) {
518 std::map<u32, std::string> map; 518 std::map<u32, std::string> map;
519 Regs regs;
520 519
521 // TODO: MSVC does not support using offsetof() on non-static data members even though this 520 // TODO: MSVC does not support using offsetof() on non-static data members even though this
522 // is technically allowed since C++11. Hence, this functionality is disabled until 521 // is technically allowed since C++11. Hence, this functionality is disabled until
523 // MSVC properly supports it. 522 // MSVC properly supports it.
524 #ifndef _MSC_VER 523 #ifndef _MSC_VER
524 Regs regs;
525 #define ADD_FIELD(name) \ 525 #define ADD_FIELD(name) \
526 do { \ 526 do { \
527 map.insert({PICA_REG_INDEX(name), #name}); \ 527 map.insert({PICA_REG_INDEX(name), #name}); \
@@ -563,7 +563,7 @@ struct Regs {
563 return map[index]; 563 return map[index];
564 } 564 }
565 565
566 static inline int NumIds() { 566 static inline size_t NumIds() {
567 return sizeof(Regs) / sizeof(u32); 567 return sizeof(Regs) / sizeof(u32);
568 } 568 }
569 569
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,
65 65
66 // vertex positions in rasterizer coordinates 66 // vertex positions in rasterizer coordinates
67 auto FloatToFix = [](float24 flt) { 67 auto FloatToFix = [](float24 flt) {
68 return Fix12P4(flt.ToFloat32() * 16.0f); 68 return Fix12P4(static_cast<unsigned short>(flt.ToFloat32() * 16.0f));
69 }; 69 };
70 auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) { 70 auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) {
71 return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; 71 return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)};
@@ -151,9 +151,9 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
151 auto w_inverse = Math::MakeVec(float24::FromFloat32(1.f) / v0.pos.w, 151 auto w_inverse = Math::MakeVec(float24::FromFloat32(1.f) / v0.pos.w,
152 float24::FromFloat32(1.f) / v1.pos.w, 152 float24::FromFloat32(1.f) / v1.pos.w,
153 float24::FromFloat32(1.f) / v2.pos.w); 153 float24::FromFloat32(1.f) / v2.pos.w);
154 auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(w0), 154 auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)),
155 float24::FromFloat32(w1), 155 float24::FromFloat32(static_cast<float>(w1)),
156 float24::FromFloat32(w2)); 156 float24::FromFloat32(static_cast<float>(w2)));
157 157
158 float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates); 158 float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates);
159 float24 interpolated_w_inverse = Math::Dot(w_inverse, baricentric_coordinates); 159 float24 interpolated_w_inverse = Math::Dot(w_inverse, baricentric_coordinates);
@@ -195,8 +195,8 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
195 // TODO(neobrain): Not sure if this swizzling pattern is used for all textures. 195 // TODO(neobrain): Not sure if this swizzling pattern is used for all textures.
196 // To be flexible in case different but similar patterns are used, we keep this 196 // To be flexible in case different but similar patterns are used, we keep this
197 // somewhat inefficient code around for now. 197 // somewhat inefficient code around for now.
198 int s = (int)(u * float24::FromFloat32(registers.texture0.width)).ToFloat32(); 198 int s = (int)(u * float24::FromFloat32(static_cast<float>(registers.texture0.width))).ToFloat32();
199 int t = (int)(v * float24::FromFloat32(registers.texture0.height)).ToFloat32(); 199 int t = (int)(v * float24::FromFloat32(static_cast<float>(registers.texture0.height))).ToFloat32();
200 int texel_index_within_tile = 0; 200 int texel_index_within_tile = 0;
201 for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { 201 for (int block_size_index = 0; block_size_index < 3; ++block_size_index) {
202 int sub_tile_width = 1 << block_size_index; 202 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:
19 RendererBase() : m_current_fps(0), m_current_frame(0) { 19 RendererBase() : m_current_fps(0), m_current_frame(0) {
20 } 20 }
21 21
22 ~RendererBase() { 22 virtual ~RendererBase() {
23 } 23 }
24 24
25 /// Swap buffers (render frame) 25 /// 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) {
29 glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result); 29 glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result);
30 glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); 30 glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
31 31
32 std::vector<char> vertex_shader_error(info_log_length);
33 glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]);
34
35 if (info_log_length > 1) { 32 if (info_log_length > 1) {
33 std::vector<char> vertex_shader_error(info_log_length);
34 glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]);
36 DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]); 35 DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]);
37 } 36 }
38 37
@@ -46,10 +45,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
46 glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result); 45 glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result);
47 glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); 46 glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
48 47
49 std::vector<char> fragment_shader_error(info_log_length);
50 glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]);
51
52 if (info_log_length > 1) { 48 if (info_log_length > 1) {
49 std::vector<char> fragment_shader_error(info_log_length);
50 glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]);
53 DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]); 51 DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]);
54 } 52 }
55 53
@@ -65,10 +63,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
65 glGetProgramiv(program_id, GL_LINK_STATUS, &result); 63 glGetProgramiv(program_id, GL_LINK_STATUS, &result);
66 glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length); 64 glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
67 65
68 std::vector<char> program_error(std::max(info_log_length, int(1)));
69 glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]);
70
71 if (info_log_length > 1) { 66 if (info_log_length > 1) {
67 std::vector<char> program_error(info_log_length);
68 glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]);
72 DEBUG_LOG(GPU, "%s", &program_error[0]); 69 DEBUG_LOG(GPU, "%s", &program_error[0]);
73 } 70 }
74 71
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 @@
6 6
7namespace GLShaders { 7namespace GLShaders {
8 8
9static const char g_vertex_shader[] = R"( 9const char g_vertex_shader[] = R"(
10#version 150 core 10#version 150 core
11in vec3 position;
12in vec2 texCoord;
13 11
14out vec2 UV; 12in vec2 vert_position;
13in vec2 vert_tex_coord;
14out vec2 frag_tex_coord;
15 15
16mat3 window_scale = mat3( 16// This is a truncated 3x3 matrix for 2D transformations:
17 vec3(1.0, 0.0, 0.0), 17// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
18 vec3(0.0, 5.0/6.0, 0.0), // TODO(princesspeachum): replace hard-coded aspect with uniform 18// The third column performs translation.
19 vec3(0.0, 0.0, 1.0) 19// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
20 ); 20// implicitly be [0, 0, 1]
21uniform mat3x2 modelview_matrix;
21 22
22void main() { 23void main() {
23 gl_Position.xyz = window_scale * position; 24 // Multiply input position by the rotscale part of the matrix and then manually translate by
24 gl_Position.w = 1.0; 25 // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
25 26 // to `vec3(vert_position.xy, 1.0)`
26 UV = texCoord; 27 gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
27})"; 28 frag_tex_coord = vert_tex_coord;
29}
30)";
28 31
29static const char g_fragment_shader[] = R"( 32const char g_fragment_shader[] = R"(
30#version 150 core 33#version 150 core
31in vec2 UV; 34
32out vec3 color; 35in vec2 frag_tex_coord;
33uniform sampler2D sampler; 36out vec4 color;
37
38uniform sampler2D color_texture;
34 39
35void main() { 40void main() {
36 color = texture(sampler, UV).rgb; 41 color = texture(color_texture, frag_tex_coord);
37})"; 42}
43)";
38 44
39} 45}
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 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hw/gpu.h" 5#include "core/hw/gpu.h"
6 6#include "core/mem_map.h"
7#include "common/emu_window.h"
7#include "video_core/video_core.h" 8#include "video_core/video_core.h"
8#include "video_core/renderer_opengl/renderer_opengl.h" 9#include "video_core/renderer_opengl/renderer_opengl.h"
9#include "video_core/renderer_opengl/gl_shader_util.h" 10#include "video_core/renderer_opengl/gl_shader_util.h"
10#include "video_core/renderer_opengl/gl_shaders.h" 11#include "video_core/renderer_opengl/gl_shaders.h"
11 12
12#include "core/mem_map.h"
13
14#include <algorithm> 13#include <algorithm>
15 14
16static const GLfloat kViewportAspectRatio = 15/**
17 (static_cast<float>(VideoCore::kScreenTopHeight) + VideoCore::kScreenBottomHeight) / VideoCore::kScreenTopWidth; 16 * Vertex structure that the drawn screen rectangles are composed of.
18 17 */
19// Fullscreen quad dimensions 18struct ScreenRectVertex {
20static const GLfloat kTopScreenWidthNormalized = 2; 19 ScreenRectVertex(GLfloat x, GLfloat y, GLfloat u, GLfloat v) {
21static const GLfloat kTopScreenHeightNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenTopHeight) / VideoCore::kScreenTopWidth); 20 position[0] = x;
22static const GLfloat kBottomScreenWidthNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth); 21 position[1] = y;
23static const GLfloat kBottomScreenHeightNormalized = kBottomScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomHeight) / VideoCore::kScreenBottomWidth); 22 tex_coord[0] = u;
24 23 tex_coord[1] = v;
25static const GLfloat g_vbuffer_top[] = { 24 }
26 // x, y, z u, v
27 -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
28 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
29 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f,
30 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f,
31 -1.0f, kTopScreenHeightNormalized, 0.0f, 0.0f, 0.0f,
32 -1.0f, 0.0f, 0.0f, 0.0f, 1.0f
33};
34 25
35static const GLfloat g_vbuffer_bottom[] = { 26 GLfloat position[2];
36 // x, y, z u, v 27 GLfloat tex_coord[2];
37 -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f,
38 (kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 1.0f, 1.0f,
39 (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f,
40 (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f,
41 -(kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 0.0f, 0.0f,
42 -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f
43}; 28};
44 29
30/**
31 * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left
32 * corner and (width, height) on the lower-bottom.
33 *
34 * The projection part of the matrix is trivial, hence these operations are represented
35 * by a 3x2 matrix.
36 */
37static std::array<GLfloat, 3*2> MakeOrthographicMatrix(const float width, const float height) {
38 std::array<GLfloat, 3*2> matrix;
39
40 matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f;
41 matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f;
42 // Last matrix row is implicitly assumed to be [0, 0, 1].
43
44 return matrix;
45}
46
45/// RendererOpenGL constructor 47/// RendererOpenGL constructor
46RendererOpenGL::RendererOpenGL() { 48RendererOpenGL::RendererOpenGL() {
47
48 resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); 49 resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
49 resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; 50 resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight;
50
51 // Initialize screen info
52 const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0];
53 const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1];
54
55 screen_info.Top().width = VideoCore::kScreenTopWidth;
56 screen_info.Top().height = VideoCore::kScreenTopHeight;
57 screen_info.Top().stride = framebuffer_top.stride;
58 screen_info.Top().flipped_xfb_data = xfb_top_flipped;
59
60 screen_info.Bottom().width = VideoCore::kScreenBottomWidth;
61 screen_info.Bottom().height = VideoCore::kScreenBottomHeight;
62 screen_info.Bottom().stride = framebuffer_sub.stride;
63 screen_info.Bottom().flipped_xfb_data = xfb_bottom_flipped;
64} 51}
65 52
66/// RendererOpenGL destructor 53/// RendererOpenGL destructor
@@ -71,17 +58,24 @@ RendererOpenGL::~RendererOpenGL() {
71void RendererOpenGL::SwapBuffers() { 58void RendererOpenGL::SwapBuffers() {
72 render_window->MakeCurrent(); 59 render_window->MakeCurrent();
73 60
74 // EFB->XFB copy 61 for(int i : {0, 1}) {
75 // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some 62 const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
76 // register write. 63
77 // 64 if (textures[i].width != framebuffer.width || textures[i].height != framebuffer.height) {
78 // TODO(princesspeachum): (related to above^) this should only be called when there's new data, not every frame. 65 // Reallocate texture if the framebuffer size has changed.
79 // Currently this uploads data that shouldn't have changed. 66 // This is expected to not happen very often and hence should not be a
80 common::Rect framebuffer_size(0, 0, resolution_width, resolution_height); 67 // performance problem.
81 RenderXFB(framebuffer_size, framebuffer_size); 68 glBindTexture(GL_TEXTURE_2D, textures[i].handle);
69 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, framebuffer.width, framebuffer.height, 0,
70 GL_BGR, GL_UNSIGNED_BYTE, nullptr);
71 textures[i].width = framebuffer.width;
72 textures[i].height = framebuffer.height;
73 }
74
75 LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]);
76 }
82 77
83 // XFB->Window copy 78 DrawScreens();
84 RenderFramebuffer();
85 79
86 // Swap buffers 80 // Swap buffers
87 render_window->PollEvents(); 81 render_window->PollEvents();
@@ -89,144 +83,135 @@ void RendererOpenGL::SwapBuffers() {
89} 83}
90 84
91/** 85/**
92 * Helper function to flip framebuffer from left-to-right to top-to-bottom 86 * Loads framebuffer from emulated memory into the active OpenGL texture.
93 * @param raw_data Pointer to input raw framebuffer in V/RAM
94 * @param screen_info ScreenInfo structure with screen size and output buffer pointer
95 * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei
96 */ 87 */
97void RendererOpenGL::FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info) { 88void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer,
98 for (int x = 0; x < screen_info.width; x++) { 89 const TextureInfo& texture) {
99 int in_coord = x * screen_info.stride; 90 const VAddr framebuffer_vaddr = Memory::PhysicalToVirtualAddress(
100 for (int y = screen_info.height-1; y >= 0; y--) { 91 framebuffer.active_fb == 1 ? framebuffer.address_left2 : framebuffer.address_left1);
101 // TODO: Properly support other framebuffer formats 92
102 int out_coord = (x + y * screen_info.width) * 3; 93 DEBUG_LOG(GPU, "0x%08x bytes from 0x%08x(%dx%d), fmt %x",
103 screen_info.flipped_xfb_data[out_coord] = raw_data[in_coord + 2]; // Red 94 framebuffer.stride * framebuffer.height,
104 screen_info.flipped_xfb_data[out_coord + 1] = raw_data[in_coord + 1]; // Green 95 framebuffer_vaddr, (int)framebuffer.width,
105 screen_info.flipped_xfb_data[out_coord + 2] = raw_data[in_coord]; // Blue 96 (int)framebuffer.height, (int)framebuffer.format);
106 in_coord += 3; 97
107 } 98 const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr);
108 } 99
100 // TODO: Handle other pixel formats
101 _dbg_assert_msg_(RENDER, framebuffer.color_format == GPU::Regs::PixelFormat::RGB8,
102 "Unsupported 3DS pixel format.");
103
104 size_t pixel_stride = framebuffer.stride / 3;
105 // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately
106 _dbg_assert_(RENDER, pixel_stride * 3 == framebuffer.stride);
107 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
108 // only allows rows to have a memory alignement of 4.
109 _dbg_assert_(RENDER, pixel_stride % 4 == 0);
110
111 glBindTexture(GL_TEXTURE_2D, texture.handle);
112 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
113
114 // Update existing texture
115 // TODO: Test what happens on hardware when you change the framebuffer dimensions so that they
116 // differ from the LCD resolution.
117 // TODO: Applications could theoretically crash Citra here by specifying too large
118 // framebuffer sizes. We should make sure that this cannot happen.
119 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
120 GL_BGR, GL_UNSIGNED_BYTE, framebuffer_data);
121
122 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
123
124 glBindTexture(GL_TEXTURE_2D, 0);
109} 125}
110 126
111/** 127/**
112 * Renders external framebuffer (XFB) 128 * Initializes the OpenGL state and creates persistent objects.
113 * @param src_rect Source rectangle in XFB to copy
114 * @param dst_rect Destination rectangle in output framebuffer to copy to
115 */ 129 */
116void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { 130void RendererOpenGL::InitOpenGLObjects() {
117 const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0]; 131 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
118 const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1]; 132 glDisable(GL_DEPTH_TEST);
119 const u32 active_fb_top = (framebuffer_top.active_fb == 1)
120 ? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2)
121 : Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1);
122 const u32 active_fb_sub = (framebuffer_sub.active_fb == 1)
123 ? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2)
124 : Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1);
125
126 DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x",
127 framebuffer_top.stride * framebuffer_top.height,
128 active_fb_top, (int)framebuffer_top.width,
129 (int)framebuffer_top.height, (int)framebuffer_top.format);
130
131 FlipFramebuffer(Memory::GetPointer(active_fb_top), screen_info.Top());
132 FlipFramebuffer(Memory::GetPointer(active_fb_sub), screen_info.Bottom());
133
134 for (int i = 0; i < 2; i++) {
135 ScreenInfo* current_screen = &screen_info[i];
136
137 glBindTexture(GL_TEXTURE_2D, current_screen->texture_id);
138
139 // TODO: This should consider the GPU registers for framebuffer width, height and stride.
140 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, current_screen->width, current_screen->height,
141 GL_RGB, GL_UNSIGNED_BYTE, current_screen->flipped_xfb_data);
142 }
143
144 glBindTexture(GL_TEXTURE_2D, 0);
145
146 // TODO(princesspeachum):
147 // Only the subset src_rect of the GPU buffer
148 // should be copied into the texture of the relevant screen.
149 //
150 // The method's parameters also only include src_rect and dest_rec for one screen,
151 // so this may need to be changed (pair for each screen).
152}
153 133
154/// Initialize the FBO 134 // Link shaders and get variable locations
155void RendererOpenGL::InitFramebuffer() {
156 program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); 135 program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader);
157 sampler_id = glGetUniformLocation(program_id, "sampler"); 136 uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix");
158 attrib_position = glGetAttribLocation(program_id, "position"); 137 uniform_color_texture = glGetUniformLocation(program_id, "color_texture");
159 attrib_texcoord = glGetAttribLocation(program_id, "texCoord"); 138 attrib_position = glGetAttribLocation(program_id, "vert_position");
160 139 attrib_tex_coord = glGetAttribLocation(program_id, "vert_tex_coord");
161 // Generate vertex buffers for both screens
162 glGenBuffers(1, &screen_info.Top().vertex_buffer_id);
163 glGenBuffers(1, &screen_info.Bottom().vertex_buffer_id);
164
165 // Attach vertex data for top screen
166 glBindBuffer(GL_ARRAY_BUFFER, screen_info.Top().vertex_buffer_id);
167 glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_top), g_vbuffer_top, GL_STATIC_DRAW);
168
169 // Attach vertex data for bottom screen
170 glBindBuffer(GL_ARRAY_BUFFER, screen_info.Bottom().vertex_buffer_id);
171 glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_bottom), g_vbuffer_bottom, GL_STATIC_DRAW);
172 140
173 // Create color buffers for both screens 141 // Generate VBO handle for drawing
174 glGenTextures(1, &screen_info.Top().texture_id); 142 glGenBuffers(1, &vertex_buffer_handle);
175 glGenTextures(1, &screen_info.Bottom().texture_id);
176 143
177 for (int i = 0; i < 2; i++) { 144 // Generate VAO
145 glGenVertexArrays(1, &vertex_array_handle);
146 glBindVertexArray(vertex_array_handle);
147
148 // Attach vertex data to VAO
149 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle);
150 glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
151 glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, position));
152 glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, tex_coord));
153 glEnableVertexAttribArray(attrib_position);
154 glEnableVertexAttribArray(attrib_tex_coord);
178 155
179 ScreenInfo* current_screen = &screen_info[i]; 156 // Allocate textures for each screen
157 for (auto& texture : textures) {
158 glGenTextures(1, &texture.handle);
180 159
181 // Allocate texture 160 // Allocation of storage is deferred until the first frame, when we
182 glBindTexture(GL_TEXTURE_2D, current_screen->vertex_buffer_id); 161 // know the framebuffer size.
183 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, current_screen->width, current_screen->height,
184 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
185 162
163 glBindTexture(GL_TEXTURE_2D, texture.handle);
164 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
186 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 165 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
187 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 166 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
188 } 169 }
189
190 glBindTexture(GL_TEXTURE_2D, 0); 170 glBindTexture(GL_TEXTURE_2D, 0);
191} 171}
192 172
193void RendererOpenGL::RenderFramebuffer() { 173/**
174 * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation.
175 */
176void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h) {
177 std::array<ScreenRectVertex, 4> vertices = {
178 ScreenRectVertex(x, y, 1.f, 0.f),
179 ScreenRectVertex(x+w, y, 1.f, 1.f),
180 ScreenRectVertex(x, y+h, 0.f, 0.f),
181 ScreenRectVertex(x+w, y+h, 0.f, 1.f),
182 };
183
184 glBindTexture(GL_TEXTURE_2D, texture.handle);
185 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle);
186 glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
187 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
188}
189
190/**
191 * Draws the emulated screens to the emulator window.
192 */
193void RendererOpenGL::DrawScreens() {
194 glViewport(0, 0, resolution_width, resolution_height); 194 glViewport(0, 0, resolution_width, resolution_height);
195 glClear(GL_COLOR_BUFFER_BIT); 195 glClear(GL_COLOR_BUFFER_BIT);
196 196
197 glUseProgram(program_id); 197 glUseProgram(program_id);
198 198
199 // Set projection matrix
200 std::array<GLfloat, 3*2> ortho_matrix = MakeOrthographicMatrix((float)resolution_width, (float)resolution_height);
201 glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
202
199 // Bind texture in Texture Unit 0 203 // Bind texture in Texture Unit 0
200 glActiveTexture(GL_TEXTURE0); 204 glActiveTexture(GL_TEXTURE0);
205 glUniform1i(uniform_color_texture, 0);
201 206
202 glEnableVertexAttribArray(attrib_position); 207 const float max_width = std::max((float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenBottomWidth);
203 glEnableVertexAttribArray(attrib_texcoord); 208 const float top_x = 0.5f * (max_width - VideoCore::kScreenTopWidth);
204 209 const float bottom_x = 0.5f * (max_width - VideoCore::kScreenBottomWidth);
205 for (int i = 0; i < 2; i++) {
206 210
207 ScreenInfo* current_screen = &screen_info[i]; 211 DrawSingleScreenRotated(textures[0], top_x, 0,
208 212 (float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenTopHeight);
209 glBindTexture(GL_TEXTURE_2D, current_screen->texture_id); 213 DrawSingleScreenRotated(textures[1], bottom_x, (float)VideoCore::kScreenTopHeight,
210 214 (float)VideoCore::kScreenBottomWidth, (float)VideoCore::kScreenBottomHeight);
211 // Set sampler on Texture Unit 0
212 glUniform1i(sampler_id, 0);
213
214 glBindBuffer(GL_ARRAY_BUFFER, current_screen->vertex_buffer_id);
215
216 // Vertex buffer layout
217 const GLsizei stride = 5 * sizeof(GLfloat);
218 const GLvoid* uv_offset = (const GLvoid*)(3 * sizeof(GLfloat));
219
220 // Configure vertex buffer
221 glVertexAttribPointer(attrib_position, 3, GL_FLOAT, GL_FALSE, stride, NULL);
222 glVertexAttribPointer(attrib_texcoord, 2, GL_FLOAT, GL_FALSE, stride, uv_offset);
223
224 // Draw screen
225 glDrawArrays(GL_TRIANGLES, 0, 6);
226 }
227
228 glDisableVertexAttribArray(attrib_position);
229 glDisableVertexAttribArray(attrib_texcoord);
230 215
231 m_current_frame++; 216 m_current_frame++;
232} 217}
@@ -253,20 +238,8 @@ void RendererOpenGL::Init() {
253 exit(-1); 238 exit(-1);
254 } 239 }
255 240
256 // Generate VAO
257 glGenVertexArrays(1, &vertex_array_id);
258 glBindVertexArray(vertex_array_id);
259
260 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
261 glDisable(GL_DEPTH_TEST);
262
263 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
264
265 // Initialize everything else
266 // --------------------------
267 InitFramebuffer();
268
269 NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); 241 NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION));
242 InitOpenGLObjects();
270} 243}
271 244
272/// Shutdown the renderer 245/// 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 @@
7#include "generated/gl_3_2_core.h" 7#include "generated/gl_3_2_core.h"
8 8
9#include "common/common.h" 9#include "common/common.h"
10#include "common/emu_window.h" 10#include "core/hw/gpu.h"
11
12#include "video_core/renderer_base.h" 11#include "video_core/renderer_base.h"
13 12
14#include <array> 13#include <array>
15 14
16class RendererOpenGL : virtual public RendererBase { 15class EmuWindow;
16
17class RendererOpenGL : public RendererBase {
17public: 18public:
18 19
19 RendererOpenGL(); 20 RendererOpenGL();
20 ~RendererOpenGL(); 21 ~RendererOpenGL() override;
21 22
22 /// Swap buffers (render frame) 23 /// Swap buffers (render frame)
23 void SwapBuffers(); 24 void SwapBuffers() override;
24
25 /**
26 * Renders external framebuffer (XFB)
27 * @param src_rect Source rectangle in XFB to copy
28 * @param dst_rect Destination rectangle in output framebuffer to copy to
29 */
30 void RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect);
31 25
32 /** 26 /**
33 * Set the emulator window to use for renderer 27 * Set the emulator window to use for renderer
34 * @param window EmuWindow handle to emulator window to use for rendering 28 * @param window EmuWindow handle to emulator window to use for rendering
35 */ 29 */
36 void SetWindow(EmuWindow* window); 30 void SetWindow(EmuWindow* window) override;
37 31
38 /// Initialize the renderer 32 /// Initialize the renderer
39 void Init(); 33 void Init() override;
40 34
41 /// Shutdown the renderer 35 /// Shutdown the renderer
42 void ShutDown(); 36 void ShutDown() override;
43 37
44private: 38private:
39 /// Structure used for storing information about the textures for each 3DS screen
40 struct TextureInfo {
41 GLuint handle;
42 GLsizei width;
43 GLsizei height;
44 };
45 45
46 /// Initialize the FBO 46 void InitOpenGLObjects();
47 void InitFramebuffer(); 47 void DrawScreens();
48 48 void DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h);
49 // Blit the FBO to the OpenGL default framebuffer
50 void RenderFramebuffer();
51
52 /// Updates the framerate
53 void UpdateFramerate(); 49 void UpdateFramerate();
54 50
55 /// Structure used for storing information for rendering each 3DS screen 51 // Loads framebuffer from emulated memory into the active OpenGL texture.
56 struct ScreenInfo { 52 static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer,
57 // Properties 53 const TextureInfo& texture);
58 int width;
59 int height;
60 int stride; ///< Number of bytes between the coordinates (0,0) and (1,0)
61
62 // OpenGL object IDs
63 GLuint texture_id;
64 GLuint vertex_buffer_id;
65
66 // Temporary
67 u8* flipped_xfb_data;
68 };
69
70 /**
71 * Helper function to flip framebuffer from left-to-right to top-to-bottom
72 * @param raw_data Pointer to input raw framebuffer in V/RAM
73 * @param screen_info ScreenInfo structure with screen size and output buffer pointer
74 * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei
75 */
76 void FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info);
77 54
78 EmuWindow* render_window; ///< Handle to render window 55 EmuWindow* render_window; ///< Handle to render window
79 u32 last_mode; ///< Last render mode 56 u32 last_mode; ///< Last render mode
@@ -81,22 +58,15 @@ private:
81 int resolution_width; ///< Current resolution width 58 int resolution_width; ///< Current resolution width
82 int resolution_height; ///< Current resolution height 59 int resolution_height; ///< Current resolution height
83 60
84 // OpenGL global object IDs 61 // OpenGL object IDs
85 GLuint vertex_array_id; 62 GLuint vertex_array_handle;
63 GLuint vertex_buffer_handle;
86 GLuint program_id; 64 GLuint program_id;
87 GLuint sampler_id; 65 std::array<TextureInfo, 2> textures;
66 // Shader uniform location indices
67 GLuint uniform_modelview_matrix;
68 GLuint uniform_color_texture;
88 // Shader attribute input indices 69 // Shader attribute input indices
89 GLuint attrib_position; 70 GLuint attrib_position;
90 GLuint attrib_texcoord; 71 GLuint attrib_tex_coord;
91
92 struct : std::array<ScreenInfo, 2> {
93 ScreenInfo& Top() { return (*this)[0]; }
94 ScreenInfo& Bottom() { return (*this)[1]; }
95 } screen_info;
96
97 // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom
98 // as OpenGL expects them in a texture. There probably is a more efficient way of doing this:
99 u8 xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4];
100 u8 xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4];
101
102}; 72};
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 @@
8#include "video_core/utils.h" 8#include "video_core/utils.h"
9 9
10namespace VideoCore { 10namespace VideoCore {
11
11/** 12/**
12 * Dumps a texture to TGA 13 * Dumps a texture to TGA
13 * @param filename String filename to dump texture to 14 * @param filename String filename to dump texture to
@@ -16,29 +17,20 @@ namespace VideoCore {
16 * @param raw_data Raw RGBA8 texture data to dump 17 * @param raw_data Raw RGBA8 texture data to dump
17 * @todo This should be moved to some general purpose/common code 18 * @todo This should be moved to some general purpose/common code
18 */ 19 */
19void DumpTGA(std::string filename, int width, int height, u8* raw_data) { 20void DumpTGA(std::string filename, short width, short height, u8* raw_data) {
20 TGAHeader hdr; 21 TGAHeader hdr = {0, 0, 2, 0, 0, 0, 0, width, height, 24, 0};
21 FILE* fout; 22 FILE* fout = fopen(filename.c_str(), "wb");
22 u8 r, g, b; 23
23
24 memset(&hdr, 0, sizeof(hdr));
25 hdr.datatypecode = 2; // uncompressed RGB
26 hdr.bitsperpixel = 24; // 24 bpp
27 hdr.width = width;
28 hdr.height = height;
29
30 fout = fopen(filename.c_str(), "wb");
31 fwrite(&hdr, sizeof(TGAHeader), 1, fout); 24 fwrite(&hdr, sizeof(TGAHeader), 1, fout);
32 for (int i = 0; i < height; i++) { 25
33 for (int j = 0; j < width; j++) { 26 for (int y = 0; y < height; y++) {
34 b = raw_data[(3 * (i * width)) + (3 * j) + 0]; 27 for (int x = 0; x < width; x++) {
35 g = raw_data[(3 * (i * width)) + (3 * j) + 1]; 28 putc(raw_data[(3 * (y * width)) + (3 * x) + 0], fout); // b
36 r = raw_data[(3 * (i * width)) + (3 * j) + 2]; 29 putc(raw_data[(3 * (y * width)) + (3 * x) + 1], fout); // g
37 putc(b, fout); 30 putc(raw_data[(3 * (y * width)) + (3 * x) + 2], fout); // r
38 putc(g, fout);
39 putc(r, fout);
40 } 31 }
41 } 32 }
33
42 fclose(fout); 34 fclose(fout);
43} 35}
44} // namespace 36} // 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 {
59 * @param raw_data Raw RGBA8 texture data to dump 59 * @param raw_data Raw RGBA8 texture data to dump
60 * @todo This should be moved to some general purpose/common code 60 * @todo This should be moved to some general purpose/common code
61 */ 61 */
62void DumpTGA(std::string filename, int width, int height, u8* raw_data); 62void DumpTGA(std::string filename, short width, short height, u8* raw_data);
63 63
64} // namespace 64} // 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) {
77 : nullptr; 77 : nullptr;
78 78
79 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; 79 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id];
80 const bool negate_src1 = swizzle.negate; 80 const bool negate_src1 = (swizzle.negate != 0);
81 81
82 float24 src1[4] = { 82 float24 src1[4] = {
83 src1_[(int)swizzle.GetSelectorSrc1(0)], 83 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 {
225 } 225 }
226 226
227 bool DestComponentEnabled(int i) const { 227 bool DestComponentEnabled(int i) const {
228 return (dest_mask & (0x8 >> i)); 228 return (dest_mask & (0x8 >> i)) != 0;
229 } 229 }
230 230
231 std::string SelectorToString(bool src2) const { 231 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
21RendererBase* g_renderer = NULL; ///< Renderer plugin 21RendererBase* g_renderer = NULL; ///< Renderer plugin
22int g_current_frame = 0; 22int g_current_frame = 0;
23 23
24/// Start the video core
25void Start() {
26 if (g_emu_window == NULL) {
27 ERROR_LOG(VIDEO, "VideoCore::Start called without calling Init()!");
28 }
29}
30
31/// Initialize the video core 24/// Initialize the video core
32void Init(EmuWindow* emu_window) { 25void Init(EmuWindow* emu_window) {
33 g_emu_window = emu_window; 26 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 {
17// 3DS Video Constants 17// 3DS Video Constants
18// ------------------- 18// -------------------
19 19
20// NOTE: The LCDs actually rotate the image 90 degrees when displaying. Because of that the
21// framebuffers in video memory are stored in column-major order and rendered sideways, causing
22// the widths and heights of the framebuffers read by the LCD to be switched compared to the
23// heights and widths of the screens listed here.
20static const int kScreenTopWidth = 400; ///< 3DS top screen width 24static const int kScreenTopWidth = 400; ///< 3DS top screen width
21static const int kScreenTopHeight = 240; ///< 3DS top screen height 25static const int kScreenTopHeight = 240; ///< 3DS top screen height
22static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width 26static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width
@@ -27,6 +31,7 @@ static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height
27 31
28extern RendererBase* g_renderer; ///< Renderer plugin 32extern RendererBase* g_renderer; ///< Renderer plugin
29extern int g_current_frame; ///< Current frame 33extern int g_current_frame; ///< Current frame
34extern EmuWindow* g_emu_window; ///< Emu window
30 35
31/// Start the video core 36/// Start the video core
32void Start(); 37void Start();