aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Doxyfile2369
-rw-r--r--doc-icon.pngbin0 -> 8791 bytes
-rw-r--r--src/citra/config.cpp7
-rw-r--r--src/citra/config.h1
-rw-r--r--src/citra/default_ini.h4
-rw-r--r--src/citra/emu_window/emu_window_glfw.h8
-rw-r--r--src/citra_qt/bootmanager.cpp25
-rw-r--r--src/citra_qt/bootmanager.hxx16
-rw-r--r--src/citra_qt/config.cpp17
-rw-r--r--src/citra_qt/config.h3
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.hxx2
-rw-r--r--src/citra_qt/main.cpp13
-rw-r--r--src/citra_qt/main.hxx2
-rw-r--r--src/common/console_listener.h2
-rw-r--r--src/common/key_map.h2
-rw-r--r--src/common/log_manager.h4
-rw-r--r--src/common/string_util.cpp158
-rw-r--r--src/common/string_util.h8
-rw-r--r--src/common/swap.h1
-rw-r--r--src/core/CMakeLists.txt40
-rw-r--r--src/core/arm/arm_interface.h2
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp11
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h14
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp115
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.h2
-rw-r--r--src/core/arm/interpreter/arm_interpreter.h22
-rw-r--r--src/core/arm/interpreter/armemu.cpp276
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp476
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h24
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h9
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp2055
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp1944
-rw-r--r--src/core/core.cpp17
-rw-r--r--src/core/core.h17
-rw-r--r--src/core/file_sys/archive.h106
-rw-r--r--src/core/file_sys/archive_romfs.cpp12
-rw-r--r--src/core/file_sys/archive_romfs.h7
-rw-r--r--src/core/file_sys/archive_sdmc.cpp9
-rw-r--r--src/core/file_sys/archive_sdmc.h7
-rw-r--r--src/core/file_sys/directory_sdmc.cpp2
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp8
-rw-r--r--src/core/hle/kernel/archive.cpp51
-rw-r--r--src/core/hle/kernel/archive.h12
-rw-r--r--src/core/hle/kernel/event.cpp8
-rw-r--r--src/core/hle/kernel/mutex.cpp10
-rw-r--r--src/core/hle/kernel/shared_memory.cpp8
-rw-r--r--src/core/hle/kernel/thread.cpp8
-rw-r--r--src/core/hle/service/ac_u.cpp44
-rw-r--r--src/core/hle/service/ac_u.h29
-rw-r--r--src/core/hle/service/apt_u.cpp (renamed from src/core/hle/service/apt.cpp)111
-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_user.cpp (renamed from src/core/hle/service/fs.cpp)202
-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)2
-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_user.cpp (renamed from src/core/hle/service/hid.cpp)6
-rw-r--r--src/core/hle/service/hid_user.h (renamed from src/core/hle/service/hid.h)2
-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)2
-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.cpp30
-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.cpp2
-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.cpp6
-rw-r--r--src/core/hw/gpu.cpp13
-rw-r--r--src/core/hw/gpu.h3
-rw-r--r--src/core/hw/hw.cpp4
-rw-r--r--src/core/hw/ndma.cpp4
-rw-r--r--src/core/settings.h6
-rw-r--r--src/video_core/clipper.cpp4
-rw-r--r--src/video_core/command_processor.cpp2
-rw-r--r--src/video_core/gpu_debugger.h2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h8
92 files changed, 6507 insertions, 2518 deletions
diff --git a/.gitignore b/.gitignore
index cc8abe9f..659736ff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# Build directory
build/
+doc-build/
# Generated source files
src/common/scm_rev.cpp
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 00000000..981121d9
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2369 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = Citra
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "Nintendo 3DS emulator/debugger"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO = doc-icon.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = doc-build/
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = YES
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = YES
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = NO
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = src/
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = YES
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doc-icon.png b/doc-icon.png
new file mode 100644
index 00000000..420b1546
--- /dev/null
+++ b/doc-icon.png
Binary files differ
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 65edcfc9..f45d09fc 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -7,6 +7,7 @@
#include "citra/default_ini.h"
#include "common/file_util.h"
#include "core/settings.h"
+#include "core/core.h"
#include "config.h"
@@ -55,6 +56,11 @@ void Config::ReadControls() {
Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT);
}
+void Config::ReadCore() {
+ Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter);
+ Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 60);
+}
+
void Config::ReadData() {
Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true);
}
@@ -66,6 +72,7 @@ void Config::ReadMiscellaneous() {
void Config::Reload() {
LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file);
ReadControls();
+ ReadCore();
ReadData();
ReadMiscellaneous();
}
diff --git a/src/citra/config.h b/src/citra/config.h
index 63b5978e..19bb8370 100644
--- a/src/citra/config.h
+++ b/src/citra/config.h
@@ -16,6 +16,7 @@ class Config {
bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true);
void ReadControls();
+ void ReadCore();
void ReadData();
void ReadMiscellaneous();
public:
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index 1f0b6cad..f1f626ee 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -26,6 +26,10 @@ pad_sdown =
pad_sleft =
pad_sright =
+[Core]
+cpu_core = ## 0: Interpreter (default), 1: FastInterpreter (experimental)
+gpu_refresh_rate = ## 60 (default)
+
[Data Storage]
use_virtual_sd =
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h
index 638e026e..7c307214 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -14,16 +14,16 @@ public:
~EmuWindow_GLFW();
/// Swap buffers to display the next frame
- void SwapBuffers();
+ void SwapBuffers() override;
/// Polls window events
- void PollEvents();
+ void PollEvents() override;
/// Makes the graphics context current for the caller thread
- void MakeCurrent();
+ void MakeCurrent() override;
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
- void DoneCurrent();
+ void DoneCurrent() override;
static void OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods);
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 0430aa1e..20824692 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -33,19 +33,16 @@ void EmuThread::run()
stop_run = false;
while (!stop_run)
{
- for (int tight_loop = 0; tight_loop < 10000; ++tight_loop)
+ if (cpu_running)
{
- if (cpu_running || exec_cpu_step)
- {
- if (exec_cpu_step)
- exec_cpu_step = false;
-
- Core::SingleStep();
- if (!cpu_running) {
- emit CPUStepped();
- yieldCurrentThread();
- }
- }
+ Core::RunLoop();
+ }
+ else if (exec_cpu_step)
+ {
+ exec_cpu_step = false;
+ Core::SingleStep();
+ emit CPUStepped();
+ yieldCurrentThread();
}
}
render_window->moveContext();
@@ -90,10 +87,10 @@ public:
parent_ = parent;
}
- void paintEvent(QPaintEvent* ev)
+ void paintEvent(QPaintEvent* ev) override
{
}
- void resizeEvent(QResizeEvent* ev) {
+ void resizeEvent(QResizeEvent* ev) override {
parent_->SetClientAreaWidth(size().width());
parent_->SetClientAreaHeight(size().height());
}
diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx
index 816ffed2..f8afc403 100644
--- a/src/citra_qt/bootmanager.hxx
+++ b/src/citra_qt/bootmanager.hxx
@@ -25,7 +25,7 @@ public:
*
* @warning Only call when not running!
*/
- void run();
+ void run() override;
/**
* Allow the CPU to process a single instruction (if cpu is not running)
@@ -89,13 +89,13 @@ public:
GRenderWindow(QWidget* parent = NULL);
~GRenderWindow();
- void closeEvent(QCloseEvent*);
+ void closeEvent(QCloseEvent*) override;
// EmuWindow implementation
- void SwapBuffers();
- void MakeCurrent();
- void DoneCurrent();
- void PollEvents();
+ void SwapBuffers() override;
+ void MakeCurrent() override;
+ void DoneCurrent() override;
+ void PollEvents() override;
void BackupGeometry();
void RestoreGeometry();
@@ -104,8 +104,8 @@ public:
EmuThread& GetEmuThread();
- void keyPressEvent(QKeyEvent* event);
- void keyReleaseEvent(QKeyEvent* event);
+ void keyPressEvent(QKeyEvent* event) override;
+ void keyReleaseEvent(QKeyEvent* event) override;
void ReloadSetKeymaps() override;
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 0ebc15f1..09fce4d6 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -6,6 +6,7 @@
#include <QStringList>
#include "core/settings.h"
+#include "core/core.h"
#include "common/file_util.h"
#include "config.h"
@@ -64,6 +65,20 @@ void Config::SaveControls() {
qt_config->endGroup();
}
+void Config::ReadCore() {
+ qt_config->beginGroup("Core");
+ Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt();
+ Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 60).toInt();
+ qt_config->endGroup();
+}
+
+void Config::SaveCore() {
+ qt_config->beginGroup("Core");
+ qt_config->setValue("cpu_core", Settings::values.cpu_core);
+ qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate);
+ qt_config->endGroup();
+}
+
void Config::ReadData() {
qt_config->beginGroup("Data Storage");
Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
@@ -90,12 +105,14 @@ void Config::SaveMiscellaneous() {
void Config::Reload() {
ReadControls();
+ ReadCore();
ReadData();
ReadMiscellaneous();
}
void Config::Save() {
SaveControls();
+ SaveCore();
SaveData();
SaveMiscellaneous();
}
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h
index 97990246..8c6568cb 100644
--- a/src/citra_qt/config.h
+++ b/src/citra_qt/config.h
@@ -14,7 +14,8 @@ class Config {
void ReadControls();
void SaveControls();
-
+ void ReadCore();
+ void SaveCore();
void ReadData();
void SaveData();
diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx
index 479ef032..1523e724 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.hxx
+++ b/src/citra_qt/debugger/graphics_cmdlists.hxx
@@ -17,7 +17,7 @@ class GPUCommandListModel : public QAbstractListModel
public:
GPUCommandListModel(QObject* parent);
- int columnCount(const QModelIndex& parent = QModelIndex()) const;
+ int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index c99f9283..9a4e36ad 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -121,7 +121,10 @@ GMainWindow::GMainWindow()
show();
- System::Init(render_window);
+ QStringList args = QApplication::arguments();
+ if (args.length() >= 2) {
+ BootGame(args[1].toStdString());
+ }
}
GMainWindow::~GMainWindow()
@@ -133,10 +136,11 @@ GMainWindow::~GMainWindow()
void GMainWindow::BootGame(std::string filename)
{
- NOTICE_LOG(MASTER_LOG, "citra starting...\n");
+ NOTICE_LOG(MASTER_LOG, "Citra starting...\n");
+ System::Init(render_window);
if (Core::Init()) {
- ERROR_LOG(MASTER_LOG, "core initialization failed, exiting...");
+ ERROR_LOG(MASTER_LOG, "Core initialization failed, exiting...");
Core::Stop();
exit(1);
}
@@ -154,6 +158,7 @@ void GMainWindow::BootGame(std::string filename)
render_window->GetEmuThread().start();
render_window->show();
+ OnStartGame();
}
void GMainWindow::OnMenuLoadFile()
@@ -190,6 +195,7 @@ void GMainWindow::OnPauseGame()
void GMainWindow::OnStopGame()
{
render_window->GetEmuThread().SetCpuRunning(false);
+ // TODO: Shutdown core
ui.action_Start->setEnabled(true);
ui.action_Pause->setEnabled(false);
@@ -251,7 +257,6 @@ int __cdecl main(int argc, char* argv[])
QApplication::setAttribute(Qt::AA_X11InitThreads);
QApplication app(argc, argv);
GMainWindow main_window;
-
main_window.show();
return app.exec();
}
diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx
index a0b41f5f..b1b40df4 100644
--- a/src/citra_qt/main.hxx
+++ b/src/citra_qt/main.hxx
@@ -32,7 +32,7 @@ public:
private:
void BootGame(std::string filename);
- void closeEvent(QCloseEvent* event);
+ void closeEvent(QCloseEvent* event) override;
private slots:
void OnStartGame();
diff --git a/src/common/console_listener.h b/src/common/console_listener.h
index 3c0e420c..ebd90a10 100644
--- a/src/common/console_listener.h
+++ b/src/common/console_listener.h
@@ -26,7 +26,7 @@ public:
#ifdef _WIN32
COORD GetCoordinates(int BytesRead, int BufferWidth);
#endif
- void Log(LogTypes::LOG_LEVELS, const char *Text);
+ void Log(LogTypes::LOG_LEVELS, const char *Text) override;
void ClearScreen(bool Cursor = true);
private:
diff --git a/src/common/key_map.h b/src/common/key_map.h
index b5acfbab..bf72362c 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -4,7 +4,7 @@
#pragma once
-#include "core/hle/service/hid.h"
+#include "core/hle/service/hid_user.h"
namespace KeyMap {
diff --git a/src/common/log_manager.h b/src/common/log_manager.h
index ce62d036..de1d16ee 100644
--- a/src/common/log_manager.h
+++ b/src/common/log_manager.h
@@ -30,7 +30,7 @@ class FileLogListener : public LogListener
public:
FileLogListener(const char *filename);
- void Log(LogTypes::LOG_LEVELS, const char *msg);
+ void Log(LogTypes::LOG_LEVELS, const char *msg) override;
bool IsValid() { return !m_logfile.fail(); }
bool IsEnabled() const { return m_enable; }
@@ -47,7 +47,7 @@ private:
class DebuggerLogListener : public LogListener
{
public:
- void Log(LogTypes::LOG_LEVELS, const char *msg);
+ void Log(LogTypes::LOG_LEVELS, const char *msg) override;
};
class LogContainer
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 61f0939c..54943d30 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -9,6 +9,7 @@
#ifdef _WIN32
#include <Windows.h>
+ #include <codecvt>
#else
#include <iconv.h>
#endif
@@ -411,7 +412,19 @@ std::string UriEncode(const std::string & sSrc)
#ifdef _WIN32
-std::string UTF16ToUTF8(const std::wstring& input)
+std::string UTF16ToUTF8(const std::u16string& input)
+{
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+ return convert.to_bytes(input);
+}
+
+std::u16string UTF8ToUTF16(const std::string& input)
+{
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+ return convert.from_bytes(input);
+}
+
+static std::string UTF16ToUTF8(const std::wstring& input)
{
auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr);
@@ -424,7 +437,7 @@ std::string UTF16ToUTF8(const std::wstring& input)
return output;
}
-std::wstring CPToUTF16(u32 code_page, const std::string& input)
+static std::wstring CPToUTF16(u32 code_page, const std::string& input)
{
auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0);
@@ -437,7 +450,7 @@ std::wstring CPToUTF16(u32 code_page, const std::string& input)
return output;
}
-std::wstring UTF8ToUTF16(const std::string& input)
+std::wstring UTF8ToUTF16W(const std::string &input)
{
return CPToUTF16(CP_UTF8, input);
}
@@ -455,61 +468,123 @@ std::string CP1252ToUTF8(const std::string& input)
#else
template <typename T>
-std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
+static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
{
std::string result;
iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
- if ((iconv_t)-1 == conv_desc)
+ if ((iconv_t)(-1) == conv_desc)
{
ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
+ iconv_close(conv_desc);
+ return {};
}
- else
- {
- size_t const in_bytes = sizeof(T) * input.size();
- size_t const out_buffer_size = 4 * in_bytes;
- std::string out_buffer;
- out_buffer.resize(out_buffer_size);
+ const size_t in_bytes = sizeof(T) * input.size();
+ // Multiply by 4, which is the max number of bytes to encode a codepoint
+ const size_t out_buffer_size = 4 * in_bytes;
- auto src_buffer = &input[0];
- size_t src_bytes = in_bytes;
- auto dst_buffer = &out_buffer[0];
- size_t dst_bytes = out_buffer.size();
+ std::string out_buffer;
+ out_buffer.resize(out_buffer_size);
- while (src_bytes != 0)
- {
- size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
- &dst_buffer, &dst_bytes);
+ auto src_buffer = &input[0];
+ size_t src_bytes = in_bytes;
+ auto dst_buffer = &out_buffer[0];
+ size_t dst_bytes = out_buffer.size();
- if ((size_t)-1 == iconv_result)
+ while (0 != src_bytes)
+ {
+ size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
+ &dst_buffer, &dst_bytes);
+
+ if (static_cast<size_t>(-1) == iconv_result)
+ {
+ if (EILSEQ == errno || EINVAL == errno)
{
- if (EILSEQ == errno || EINVAL == errno)
+ // Try to skip the bad character
+ if (0 != src_bytes)
{
- // Try to skip the bad character
- if (src_bytes != 0)
- {
- --src_bytes;
- ++src_buffer;
- }
- }
- else
- {
- ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno));
- break;
+ --src_bytes;
+ ++src_buffer;
}
}
+ else
+ {
+ ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno));
+ break;
+ }
}
+ }
- out_buffer.resize(out_buffer_size - dst_bytes);
- out_buffer.swap(result);
-
+ out_buffer.resize(out_buffer_size - dst_bytes);
+ out_buffer.swap(result);
+
+ iconv_close(conv_desc);
+
+ return result;
+}
+
+std::u16string UTF8ToUTF16(const std::string& input)
+{
+ std::u16string result;
+
+ iconv_t const conv_desc = iconv_open("UTF-16", "UTF-8");
+ if ((iconv_t)(-1) == conv_desc)
+ {
+ ERROR_LOG(COMMON, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
iconv_close(conv_desc);
+ return {};
}
+
+ const size_t in_bytes = sizeof(char) * input.size();
+ // Multiply by 4, which is the max number of bytes to encode a codepoint
+ const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes;
+
+ std::u16string out_buffer;
+ out_buffer.resize(out_buffer_size);
+
+ char* src_buffer = const_cast<char*>(&input[0]);
+ size_t src_bytes = in_bytes;
+ char* dst_buffer = (char*)(&out_buffer[0]);
+ size_t dst_bytes = out_buffer.size();
+
+ while (0 != src_bytes)
+ {
+ size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes,
+ &dst_buffer, &dst_bytes);
+
+ if (static_cast<size_t>(-1) == iconv_result)
+ {
+ if (EILSEQ == errno || EINVAL == errno)
+ {
+ // Try to skip the bad character
+ if (0 != src_bytes)
+ {
+ --src_bytes;
+ ++src_buffer;
+ }
+ }
+ else
+ {
+ ERROR_LOG(COMMON, "iconv failure [UTF-8]: %s", strerror(errno));
+ break;
+ }
+ }
+ }
+
+ out_buffer.resize(out_buffer_size - dst_bytes);
+ out_buffer.swap(result);
+
+ iconv_close(conv_desc);
return result;
}
+std::string UTF16ToUTF8(const std::u16string& input)
+{
+ return CodeToUTF8("UTF-16", input);
+}
+
std::string CP1252ToUTF8(const std::string& input)
{
//return CodeToUTF8("CP1252//TRANSLIT", input);
@@ -523,19 +598,6 @@ std::string SHIFTJISToUTF8(const std::string& input)
return CodeToUTF8("SJIS", input);
}
-std::string UTF16ToUTF8(const std::wstring& input)
-{
- std::string result =
- // CodeToUTF8("UCS-2", input);
- // CodeToUTF8("UCS-2LE", input);
- // CodeToUTF8("UTF-16", input);
- CodeToUTF8("UTF-16LE", input);
-
- // TODO: why is this needed?
- result.erase(std::remove(result.begin(), result.end(), 0x00), result.end());
- return result;
-}
-
#endif
}
diff --git a/src/common/string_util.h b/src/common/string_util.h
index a41ccc69..787a5663 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -89,20 +89,22 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
std::string UriDecode(const std::string & sSrc);
std::string UriEncode(const std::string & sSrc);
+std::string UTF16ToUTF8(const std::u16string& input);
+std::u16string UTF8ToUTF16(const std::string& input);
+
std::string CP1252ToUTF8(const std::string& str);
std::string SHIFTJISToUTF8(const std::string& str);
-std::string UTF16ToUTF8(const std::wstring& str);
#ifdef _WIN32
-std::wstring UTF8ToUTF16(const std::string& str);
+std::wstring UTF8ToUTF16W(const std::string& str);
#ifdef _UNICODE
inline std::string TStrToUTF8(const std::wstring& str)
{ return UTF16ToUTF8(str); }
inline std::wstring UTF8ToTStr(const std::string& str)
-{ return UTF8ToUTF16(str); }
+{ return UTF8ToUTF16W(str); }
#else
inline std::string TStrToUTF8(const std::string& str)
{ return str; }
diff --git a/src/common/swap.h b/src/common/swap.h
index 123019fd..4f8f39ef 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -85,7 +85,6 @@ public:
return *this;
}
- operator long() const { return (long)swap(); }
operator s8() const { return (s8)swap(); }
operator u8() const { return (u8)swap(); }
operator s16() const { return (s16)swap(); }
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index aefbe337..f41d52e8 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -30,13 +30,23 @@ set(SRCS
hle/kernel/mutex.cpp
hle/kernel/shared_memory.cpp
hle/kernel/thread.cpp
- hle/service/apt.cpp
- hle/service/fs.cpp
- hle/service/gsp.cpp
- hle/service/hid.cpp
- hle/service/ndm.cpp
+ hle/service/ac_u.cpp
+ hle/service/apt_u.cpp
+ hle/service/cfg_u.cpp
+ hle/service/dsp_dsp.cpp
+ hle/service/err_f.cpp
+ hle/service/fs_user.cpp
+ hle/service/frd_u.cpp
+ hle/service/gsp_gpu.cpp
+ hle/service/hid_user.cpp
+ hle/service/mic_u.cpp
+ hle/service/ndm_u.cpp
+ hle/service/nwm_uds.cpp
+ hle/service/ptm_u.cpp
hle/service/service.cpp
+ hle/service/soc_u.cpp
hle/service/srv.cpp
+ hle/service/ssl_c.cpp
hle/config_mem.cpp
hle/hle.cpp
hle/svc.cpp
@@ -91,13 +101,23 @@ set(HEADERS
hle/kernel/mutex.h
hle/kernel/shared_memory.h
hle/kernel/thread.h
- hle/service/apt.h
- hle/service/fs.h
- hle/service/gsp.h
- hle/service/hid.h
- hle/service/ndm.h
+ hle/service/ac_u.h
+ hle/service/apt_u.h
+ hle/service/cfg_u.h
+ hle/service/dsp_dsp.h
+ hle/service/err_f.h
+ hle/service/fs_user.h
+ hle/service/frd_u.h
+ hle/service/gsp_gpu.h
+ hle/service/hid_user.h
+ hle/service/mic_u.h
+ hle/service/ndm_u.h
+ hle/service/nwm_uds.h
+ hle/service/ptm_u.h
hle/service/service.h
+ hle/service/soc_u.h
hle/service/srv.h
+ hle/service/ssl_c.h
hle/config_mem.h
hle/function_wrappers.h
hle/hle.h
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index be677ae2..4b93d331 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -16,7 +16,7 @@ public:
num_instructions = 0;
}
- ~ARM_Interface() {
+ virtual ~ARM_Interface() {
}
/**
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 669b612f..a3ed3e31 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -60,7 +60,7 @@ void ARM_DynCom::SetPC(u32 pc) {
* @return Returns current PC
*/
u32 ARM_DynCom::GetPC() const {
- return state->pc;
+ return state->Reg[15];
}
/**
@@ -110,9 +110,12 @@ u64 ARM_DynCom::GetTicks() const {
* @param num_instructions Number of instructions to executes
*/
void ARM_DynCom::ExecuteInstructions(int num_instructions) {
- ticks += num_instructions;
state->NumInstrsToExecute = num_instructions;
- InterpreterMainLoop(state.get());
+
+ // Dyncom only breaks on instruction dispatch. This only happens on every instruction when
+ // executing one instruction at a time. Otherwise, if a block is being executed, more
+ // instructions may actually be executed than specified.
+ ticks += InterpreterMainLoop(state.get());
}
/**
@@ -126,7 +129,7 @@ void ARM_DynCom::SaveContext(ThreadContext& ctx) {
ctx.sp = state->Reg[13];
ctx.lr = state->Reg[14];
- ctx.pc = state->pc;
+ ctx.pc = state->Reg[15];
ctx.cpsr = state->Cpsr;
ctx.fpscr = state->VFP[1];
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 9f88dd13..1f8cd3a3 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -21,7 +21,7 @@ public:
* Set the Program Counter to an address
* @param addr Address to set PC to
*/
- void SetPC(u32 pc);
+ void SetPC(u32 pc) override;
/*
* Get the current Program Counter
@@ -41,7 +41,7 @@ public:
* @param index Register index (0-15)
* @param value Value to set register to
*/
- void SetReg(int index, u32 value);
+ void SetReg(int index, u32 value) override;
/**
* Get the current CPSR register
@@ -53,7 +53,7 @@ public:
* Set the current CPSR register
* @param cpsr Value to set CPSR to
*/
- void SetCPSR(u32 cpsr);
+ void SetCPSR(u32 cpsr) override;
/**
* Returns the number of clock ticks since the last reset
@@ -65,22 +65,22 @@ public:
* Saves the current CPU context
* @param ctx Thread context to save
*/
- void SaveContext(ThreadContext& ctx);
+ void SaveContext(ThreadContext& ctx) override;
/**
* Loads a CPU context
* @param ctx Thread context to load
*/
- void LoadContext(const ThreadContext& ctx);
+ void LoadContext(const ThreadContext& ctx) override;
/// Prepare core for thread reschedule (if needed to correctly handle state)
- void PrepareReschedule();
+ void PrepareReschedule() override;
/**
* Executes the given number of instructions
* @param num_instructions Number of instructions to executes
*/
- void ExecuteInstructions(int num_instructions);
+ void ExecuteInstructions(int num_instructions) override;
private:
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index fe1501b5..f899e2e8 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -3718,7 +3718,7 @@ static bool InAPrivilegedMode(arm_core_t *core)
}
/* r15 = r15 + 8 */
-void InterpreterMainLoop(ARMul_State* state)
+unsigned InterpreterMainLoop(ARMul_State* state)
{
#define CRn inst_cream->crn
#define OPCODE_2 inst_cream->opcode_2
@@ -3747,16 +3747,22 @@ void InterpreterMainLoop(ARMul_State* state)
#endif
#define FETCH_INST if (inst_base->br != NON_BRANCH) \
- goto PROFILING; \
+ goto DISPATCH; \
inst_base = (arm_inst *)&inst_buf[ptr]
#define INC_PC(l) ptr += sizeof(arm_inst) + l
// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
// clunky switch statement.
#if defined __GNUC__ || defined __clang__
-#define GOTO_NEXT_INST goto *InstLabel[inst_base->idx]
+#define GOTO_NEXT_INST \
+ if (num_instrs >= cpu->NumInstrsToExecute) goto END; \
+ num_instrs++; \
+ goto *InstLabel[inst_base->idx]
#else
-#define GOTO_NEXT_INST switch(inst_base->idx) { \
+#define GOTO_NEXT_INST \
+ if (num_instrs >= cpu->NumInstrsToExecute) goto END; \
+ num_instrs++; \
+ switch(inst_base->idx) { \
case 0: goto VMLA_INST; \
case 1: goto VMLS_INST; \
case 2: goto VNMLA_INST; \
@@ -4028,20 +4034,15 @@ void InterpreterMainLoop(ARMul_State* state)
unsigned int addr;
unsigned int phys_addr;
unsigned int last_pc = 0;
+ unsigned int num_instrs = 0;
fault_t fault;
static unsigned int last_physical_base = 0, last_logical_base = 0;
int ptr;
+ bool single_step = (cpu->NumInstrsToExecute == 1);
LOAD_NZCVT;
DISPATCH:
{
- if (cpu->NumInstrsToExecute == 0)
- return;
-
- cpu->NumInstrsToExecute--;
-
- //NOTICE_LOG(ARM11, "instr!");
-
if (!cpu->NirqSig) {
if (!(cpu->Cpsr & 0x80)) {
goto END;
@@ -4179,10 +4180,6 @@ void InterpreterMainLoop(ARMul_State* state)
inst_base = (arm_inst *)&inst_buf[ptr];
GOTO_NEXT_INST;
}
- PROFILING:
- {
- goto DISPATCH;
- }
ADC_INST:
{
INC_ICOUNTER;
@@ -4207,7 +4204,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(adc_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4241,7 +4238,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(add_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4272,7 +4269,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(and_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4290,11 +4287,11 @@ void InterpreterMainLoop(ARMul_State* state)
}
SET_PC;
INC_PC(sizeof(bbl_inst));
- goto PROFILING;
+ goto DISPATCH;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
INC_PC(sizeof(bbl_inst));
- goto PROFILING;
+ goto DISPATCH;
}
BIC_INST:
{
@@ -4322,7 +4319,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(bic_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4358,12 +4355,12 @@ void InterpreterMainLoop(ARMul_State* state)
//DEBUG_MSG;
}
INC_PC(sizeof(blx_inst));
- goto PROFILING;
+ goto DISPATCH;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
// INC_PC(sizeof(bx_inst));
INC_PC(sizeof(blx_inst));
- goto PROFILING;
+ goto DISPATCH;
}
BX_INST:
{
@@ -4376,12 +4373,12 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe;
// cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1;
INC_PC(sizeof(bx_inst));
- goto PROFILING;
+ goto DISPATCH;
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
// INC_PC(sizeof(bx_inst));
INC_PC(sizeof(bx_inst));
- goto PROFILING;
+ goto DISPATCH;
}
BXJ_INST:
CDP_INST:
@@ -4393,7 +4390,8 @@ void InterpreterMainLoop(ARMul_State* state)
#define CP_ACCESS_ALLOW 0
if(CP_ACCESS_ALLOW){
/* undefined instruction here */
- return;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
}
ERROR_LOG(ARM11, "CDP insn inst=0x%x, pc=0x%x\n", inst_cream->inst, cpu->Reg[15]);
unsigned cpab = (cpu->CDP[inst_cream->cp_num]) (cpu, ARMul_FIRST, inst_cream->inst);
@@ -4522,7 +4520,7 @@ void InterpreterMainLoop(ARMul_State* state)
// RD = RM;
if ((inst_cream->Rd == 15)) {
INC_PC(sizeof(mov_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
// DEBUG_LOG(ARM11, "cpy inst %x\n", cpu->Reg[15]);
@@ -4558,7 +4556,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(eor_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4717,7 +4715,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (BIT(inst, 15)) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4764,7 +4762,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->TFlag = value & 0x1;
cpu->Reg[15] &= 0xFFFFFFFE;
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
//}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4794,7 +4792,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->TFlag = value & 0x1;
cpu->Reg[15] &= 0xFFFFFFFE;
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4848,7 +4846,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4869,7 +4867,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4926,7 +4924,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4953,7 +4951,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -4980,7 +4978,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5006,7 +5004,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5031,7 +5029,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5058,7 +5056,7 @@ void InterpreterMainLoop(ARMul_State* state)
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5228,7 +5226,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(mla_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5260,7 +5258,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(mov_inst));
- goto PROFILING;
+ goto DISPATCH;
}
// return;
}
@@ -5422,7 +5420,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(mul_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5451,7 +5449,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(mvn_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5483,7 +5481,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(orr_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5575,7 +5573,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(rsb_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5612,7 +5610,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(rsc_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -5653,7 +5651,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(sbc_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -6066,7 +6064,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
//if (BITS(inst_cream->inst, 12, 15) == 15)
- // goto PROFILING;
+ // goto DISPATCH;
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6175,7 +6173,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
//if (BITS(inst_cream->inst, 12, 15) == 15)
- // goto PROFILING;
+ // goto DISPATCH;
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6225,7 +6223,7 @@ void InterpreterMainLoop(ARMul_State* state)
}
if (inst_cream->Rd == 15) {
INC_PC(sizeof(sub_inst));
- goto PROFILING;
+ goto DISPATCH;
}
}
cpu->Reg[15] += GET_INST_SIZE(cpu);
@@ -6449,7 +6447,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
//DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
INC_PC(sizeof(b_2_thumb));
- goto PROFILING;
+ goto DISPATCH;
}
B_COND_THUMB:
{
@@ -6461,7 +6459,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[15] += 2;
//DEBUG_LOG(ARM11, " B_COND_THUMB: imm=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[15]);
INC_PC(sizeof(b_cond_thumb));
- goto PROFILING;
+ goto DISPATCH;
}
BL_1_THUMB:
{
@@ -6487,7 +6485,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->Reg[14] = tmp;
//DEBUG_LOG(ARM11, " BL_2_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
INC_PC(sizeof(bl_2_thumb));
- goto PROFILING;
+ goto DISPATCH;
}
BLX_1_THUMB:
{
@@ -6503,7 +6501,7 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->TFlag = 0;
//DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, r15=0x%x, \n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]);
INC_PC(sizeof(blx_1_thumb));
- goto PROFILING;
+ goto DISPATCH;
}
UQADD16_INST:
@@ -6532,12 +6530,14 @@ void InterpreterMainLoop(ARMul_State* state)
cpu->AbortAddr = addr;
cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff;
cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
- return;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
}
END:
{
SAVE_NZCVT;
- return;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
}
INIT_INST_LENGTH:
{
@@ -6557,7 +6557,8 @@ void InterpreterMainLoop(ARMul_State* state)
DEBUG_LOG(ARM11, "%llx\n", InstLabel[1]);
DEBUG_LOG(ARM11, "%lld\n", (char *)InstEndLabel[1] - (char *)InstLabel[1]);
#endif
- return;
+ cpu->NumInstrsToExecute = 0;
+ return num_instrs;
}
}
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h
index d73f8f65..c65eb23f 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.h
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h
@@ -4,4 +4,4 @@
#pragma once
-void InterpreterMainLoop(ARMul_State* state);
+unsigned InterpreterMainLoop(ARMul_State* state);
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index 49ae01a0..ceb1be43 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -20,60 +20,60 @@ public:
* Set the Program Counter to an address
* @param addr Address to set PC to
*/
- void SetPC(u32 pc);
+ void SetPC(u32 pc) override;
/*
* Get the current Program Counter
* @return Returns current PC
*/
- u32 GetPC() const;
+ u32 GetPC() const override;
/**
* Get an ARM register
* @param index Register index (0-15)
* @return Returns the value in the register
*/
- u32 GetReg(int index) const;
+ u32 GetReg(int index) const override;
/**
* Set an ARM register
* @param index Register index (0-15)
* @param value Value to set register to
*/
- void SetReg(int index, u32 value);
+ void SetReg(int index, u32 value) override;
/**
* Get the current CPSR register
* @return Returns the value of the CPSR register
*/
- u32 GetCPSR() const;
+ u32 GetCPSR() const override;
/**
* Set the current CPSR register
* @param cpsr Value to set CPSR to
*/
- void SetCPSR(u32 cpsr);
+ void SetCPSR(u32 cpsr) override;
/**
* Returns the number of clock ticks since the last reset
* @return Returns number of clock ticks
*/
- u64 GetTicks() const;
+ u64 GetTicks() const override;
/**
* Saves the current CPU context
* @param ctx Thread context to save
*/
- void SaveContext(ThreadContext& ctx);
+ void SaveContext(ThreadContext& ctx) override;
/**
* Loads a CPU context
* @param ctx Thread context to load
*/
- void LoadContext(const ThreadContext& ctx);
+ void LoadContext(const ThreadContext& ctx) override;
/// Prepare core for thread reschedule (if needed to correctly handle state)
- void PrepareReschedule();
+ void PrepareReschedule() override;
protected:
@@ -81,7 +81,7 @@ protected:
* Executes the given number of instructions
* @param num_instructions Number of instructions to executes
*/
- void ExecuteInstructions(int num_instructions);
+ void ExecuteInstructions(int num_instructions) override;
private:
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index cdcf47ee..73223874 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -63,13 +63,6 @@ static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int);
static void Handle_Load_Double (ARMul_State *, ARMword);
static void Handle_Store_Double (ARMul_State *, ARMword);
-void
-XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far);
-int
-XScale_debug_moe (ARMul_State * state, int moe);
-unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg,
- unsigned cpnum);
-
static int
handle_v6_insn (ARMul_State * state, ARMword instr);
@@ -376,7 +369,7 @@ ARMul_Emulate26 (ARMul_State * state)
#endif
{
/* The PC pipeline value depends on whether ARM
- or Thumb instructions are being
+ or Thumb instructions are being
d. */
ARMword isize;
ARMword instr; /* The current instruction. */
@@ -538,6 +531,7 @@ ARMul_Emulate26 (ARMul_State * state)
state->AbortAddr = 1;
instr = ARMul_LoadInstrN (state, pc, isize);
+
//chy 2006-04-12, for ICE debug
have_bp=ARMul_ICE_debug(state,instr,pc);
#if 0
@@ -562,6 +556,7 @@ ARMul_Emulate26 (ARMul_State * state)
}
printf("\n");
#endif
+
instr = ARMul_LoadInstrN (state, pc, isize);
state->last_instr = state->CurrInstr;
state->CurrInstr = instr;
@@ -952,9 +947,8 @@ ARMul_Emulate26 (ARMul_State * state)
case t_decoded:
/* ARM instruction available. */
//printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp);
-
- if (armOp == 0xDEADC0DE)
- {
+
+ if (armOp == 0xDEADC0DE) {
DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc);
}
@@ -967,7 +961,6 @@ ARMul_Emulate26 (ARMul_State * state)
}
}
#endif
-
/* Check the condition codes. */
if ((temp = TOPBITS (28)) == AL) {
/* Vile deed in the need for speed. */
@@ -1124,6 +1117,7 @@ ARMul_Emulate26 (ARMul_State * state)
//chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it...
+
/* Actual execution of instructions begins here. */
/* If the condition codes don't match, stop here. */
if (temp) {
@@ -2308,12 +2302,9 @@ mainswitch:
if (state->Aborted) {
TAKEABORT;
}
- if (enter)
- {
+ if (enter) {
state->Reg[DESTReg] = 0;
- }
- else
- {
+ } else {
state->Reg[DESTReg] = 1;
}
break;
@@ -3063,7 +3054,27 @@ mainswitch:
break;
case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */
- if (BIT (4)) {
+ //ichfly PKHBT PKHTB todo check this
+ if ((instr & 0x70) == 0x10) //pkhbt
+ {
+ u8 idest = BITS(12, 15);
+ u8 rfis = BITS(16, 19);
+ u8 rlast = BITS(0, 3);
+ u8 ishi = BITS(7,11);
+ state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000);
+ break;
+ }
+ else if ((instr & 0x70) == 0x50)//pkhtb
+ {
+ u8 idest = BITS(12, 15);
+ u8 rfis = BITS(16, 19);
+ u8 rlast = BITS(0, 3);
+ u8 ishi = BITS(7, 11);
+ if (ishi == 0)ishi = 0x20;
+ state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000);
+ break;
+ }
+ else if (BIT (4)) {
#ifdef MODE32
if (state->is_v6
&& handle_v6_insn (state, instr))
@@ -3675,7 +3686,13 @@ mainswitch:
/* Co-Processor Data Transfers. */
case 0xc4:
- if (state->is_v5) {
+ if ((instr & 0x0FF00FF0) == 0xC400B10) //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0
+ {
+ state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)];
+ state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)];
+ break;
+ }
+ else if (state->is_v5) {
/* Reading from R15 is UNPREDICTABLE. */
if (BITS (12, 15) == 15 || BITS (16, 19) == 15)
ARMul_UndefInstr (state, instr);
@@ -3695,13 +3712,21 @@ mainswitch:
break;
case 0xc5:
- if (state->is_v5) {
+ if ((instr & 0x00000FF0) == 0xB10) //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0
+ {
+ state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1];
+ state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1];
+ break;
+ }
+ else if (state->is_v5) {
/* Writes to R15 are UNPREDICATABLE. */
if (DESTReg == 15 || LHSReg == 15)
ARMul_UndefInstr (state, instr);
/* Is access to the coprocessor allowed ? */
else if (!CP_ACCESS_ALLOWED(state, CPNum))
- ARMul_UndefInstr (state, instr);
+ {
+ ARMul_UndefInstr(state, instr);
+ }
else {
/* MRRC, ARMv5TE and up */
ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg]));
@@ -4059,9 +4084,11 @@ TEST_EMULATE:
// continue;
else if (state->Emulate != RUN)
break;
- }
- while (state->NumInstrsToExecute--);
+
+ }
+ while (state->NumInstrsToExecute);
+exit:
state->decoded = decoded;
state->loaded = loaded;
state->pc = pc;
@@ -5686,12 +5713,98 @@ L_stm_s_takeabort:
case 0x3f:
printf ("Unhandled v6 insn: rbit\n");
break;
+#endif
case 0x61:
- printf ("Unhandled v6 insn: sadd/ssub\n");
+ if ((instr & 0xFF0) == 0xf70)//ssub16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = (a1 - a2)&0xFFFF | (((b1 - b2)&0xFFFF)<< 0x10);
+ return 1;
+ }
+ else if ((instr & 0xFF0) == 0xf10)//sadd16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10);
+ return 1;
+ }
+ else if ((instr & 0xFF0) == 0xf50)//ssax
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
+ return 1;
+ }
+ else if ((instr & 0xFF0) == 0xf30)//sasx
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
+ return 1;
+ }
+ else printf ("Unhandled v6 insn: sadd/ssub\n");
break;
case 0x62:
- printf ("Unhandled v6 insn: qadd/qsub\n");
+ if ((instr & 0xFF0) == 0xf70)//QSUB16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ s32 res1 = (a1 - b1);
+ s32 res2 = (a2 - b2);
+ if (res1 > 0x7FFF) res1 = 0x7FFF;
+ if (res2 > 0x7FFF) res2 = 0x7FFF;
+ if (res1 < 0x7FFF) res1 = -0x8000;
+ if (res2 < 0x7FFF) res2 = -0x8000;
+ state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10);
+ return 1;
+ }
+ else if ((instr & 0xFF0) == 0xf10)//QADD16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src1 = BITS(16, 19);
+ u8 src2 = BITS(0, 3);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = (state->Reg[src2] & 0xFFFF);
+ s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ s32 res1 = (a1 + b1);
+ s32 res2 = (a2 + b2);
+ if (res1 > 0x7FFF) res1 = 0x7FFF;
+ if (res2 > 0x7FFF) res2 = 0x7FFF;
+ if (res1 < 0x7FFF) res1 = -0x8000;
+ if (res2 < 0x7FFF) res2 = -0x8000;
+ state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10);
+ return 1;
+ }
+ else printf ("Unhandled v6 insn: qadd/qsub\n");
break;
+#if 0
case 0x63:
printf ("Unhandled v6 insn: shadd/shsub\n");
break;
@@ -5709,10 +5822,65 @@ L_stm_s_takeabort:
break;
#endif
case 0x6c:
- printf ("Unhandled v6 insn: uxtb16/uxtab16\n");
+ if ((instr & 0xf03f0) == 0xf0070) //uxtb16
+ {
+ u8 src1 = BITS(0, 3);
+ u8 tar = BITS(12, 15);
+ u32 base = state->Reg[src1];
+ u32 shamt = BITS(9,10)* 8;
+ u32 in = ((base << (32 - shamt)) | (base >> shamt));
+ state->Reg[tar] = in & 0x00FF00FF;
+ return 1;
+ }
+ else
+ printf ("Unhandled v6 insn: uxtb16/uxtab16\n");
break;
case 0x70:
- printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n");
+ if ((instr & 0xf0d0) == 0xf010)//smuad //ichfly
+ {
+ u8 tar = BITS(16, 19);
+ u8 src1 = BITS(0, 3);
+ u8 src2 = BITS(8, 11);
+ u8 swap = BIT(5);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
+ s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = a1*a2 + b1*b2;
+ return 1;
+
+ }
+ else if ((instr & 0xf0d0) == 0xf050)//smusd
+ {
+ u8 tar = BITS(16, 19);
+ u8 src1 = BITS(0, 3);
+ u8 src2 = BITS(8, 11);
+ u8 swap = BIT(5);
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
+ s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = a1*a2 - b1*b2;
+ return 1;
+ }
+ else if ((instr & 0xd0) == 0x10)//smlad
+ {
+ u8 tar = BITS(16, 19);
+ u8 src1 = BITS(0, 3);
+ u8 src2 = BITS(8, 11);
+ u8 src3 = BITS(12, 15);
+ u8 swap = BIT(5);
+
+ u32 a3 = state->Reg[src3];
+
+ s16 a1 = (state->Reg[src1] & 0xFFFF);
+ s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
+ s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
+ s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
+ state->Reg[tar] = a1*a2 + b1*b2 + a3;
+ return 1;
+ }
+ else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n");
break;
case 0x74:
printf ("Unhandled v6 insn: smlald/smlsld\n");
@@ -5750,13 +5918,10 @@ L_stm_s_takeabort:
if (state->Aborted) {
TAKEABORT;
}
-
- if (enter)
- {
+
+ if (enter) {
state->Reg[DESTReg] = 0;
- }
- else
- {
+ } else {
state->Reg[DESTReg] = 1;
}
@@ -5795,12 +5960,9 @@ L_stm_s_takeabort:
}
- if (enter)
- {
+ if (enter) {
state->Reg[DESTReg] = 0;
- }
- else
- {
+ } else {
state->Reg[DESTReg] = 1;
}
@@ -5853,8 +6015,25 @@ L_stm_s_takeabort:
case 0x01:
case 0xf3:
- printf ("Unhandled v6 insn: ssat\n");
- return 0;
+ //ichfly
+ //SSAT16
+ {
+ u8 tar = BITS(12,15);
+ u8 src = BITS(0, 3);
+ u8 val = BITS(16, 19) + 1;
+ s16 a1 = (state->Reg[src]);
+ s16 a2 = (state->Reg[src] >> 0x10);
+ s16 min = (s16)(0x8000) >> (16 - val);
+ s16 max = 0x7FFF >> (16 - val);
+ if (min > a1) a1 = min;
+ if (max < a1) a1 = max;
+ if (min > a2) a2 = min;
+ if (max < a2) a2 = max;
+ u32 temp2 = ((u32)(a2)) << 0x10;
+ state->Reg[tar] = (a1&0xFFFF) | (temp2);
+ }
+
+ return 1;
default:
break;
}
@@ -5944,8 +6123,21 @@ L_stm_s_takeabort:
case 0x01:
case 0xf3:
- printf ("Unhandled v6 insn: usat\n");
- return 0;
+ //ichfly
+ //USAT16
+ {
+ u8 tar = BITS(12, 15);
+ u8 src = BITS(0, 3);
+ u8 val = BITS(16, 19);
+ s16 a1 = (state->Reg[src]);
+ s16 a2 = (state->Reg[src] >> 0x10);
+ s16 max = 0xFFFF >> (16 - val);
+ if (max < a1) a1 = max;
+ if (max < a2) a2 = max;
+ u32 temp2 = ((u32)(a2)) << 0x10;
+ state->Reg[tar] = (a1 & 0xFFFF) | (temp2);
+ }
+ return 1;
default:
break;
}
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index e4fa3c20..454f6009 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -28,230 +28,270 @@
#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
+#define DEBUG DBG
+
//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
unsigned
VFPInit (ARMul_State *state)
{
- state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
- VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
- state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
-
- //persistent_state = state;
- /* Reset only specify VFP_FPEXC_EN = '0' */
-
- return No_exp;
+ state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
+ VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
+ state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0;
+ state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0;
+
+ //persistent_state = state;
+ /* Reset only specify VFP_FPEXC_EN = '0' */
+
+ return 0;
}
unsigned
-VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
+VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
{
- /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (21, 23);
- int Rt = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MRC_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_MRC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
+ /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (21, 23);
+ int Rt = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MRC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MRC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
+ instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
+
+ return ARMul_CANT;
}
unsigned
-VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
+VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value)
{
- /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (21, 23);
- int Rt = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MCR_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_MCR_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
- instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
-
- return ARMul_CANT;
+ /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (21, 23);
+ int Rt = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MCR_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MCR_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
+ instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
+
+ return ARMul_CANT;
}
unsigned
-VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2)
+VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2)
{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (4, 7);
- int Rt = BITS (12, 15);
- int Rt2 = BITS (16, 19);
- int CRm = BITS (0, 3);
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_MRRC_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_MRRC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
+ /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (4, 7);
+ int Rt = BITS (12, 15);
+ int Rt2 = BITS (16, 19);
+ int CRm = BITS (0, 3);
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_MRRC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MRRC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
+ instr, CoProc, OPC_1, Rt, Rt2, CRm);
+
+ return ARMul_CANT;
}
unsigned
-VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2)
+VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2)
{
- /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (4, 7);
- int Rt = BITS (12, 15);
- int Rt2 = BITS (16, 19);
- int CRm = BITS (0, 3);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 11 || CoProc == 10)
- {
- #define VFP_MCRR_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_MCRR_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
- instr, CoProc, OPC_1, Rt, Rt2, CRm);
-
- return ARMul_CANT;
+ /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (4, 7);
+ int Rt = BITS (12, 15);
+ int Rt2 = BITS (16, 19);
+ int CRm = BITS (0, 3);
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 11 || CoProc == 10) {
+#define VFP_MCRR_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_MCRR_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
+ instr, CoProc, OPC_1, Rt, Rt2, CRm);
+
+ return ARMul_CANT;
}
unsigned
-VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value)
+VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
{
- /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int CRd = BITS (12, 15);
- int Rn = BITS (16, 19);
- int imm8 = BITS (0, 7);
- int P = BIT(24);
- int U = BIT(23);
- int D = BIT(22);
- int W = BIT(21);
-
- /* TODO check access permission */
-
- /* VSTM */
- if ( (P|U|D|W) == 0 )
- {
- DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
- }
- if (CoProc == 10 || CoProc == 11)
- {
- #if 1
- if (P == 0 && U == 0 && W == 0)
- {
- DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1);
- }
- if (P == U && W == 1)
- {
- DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1);
- }
- #endif
-
- #define VFP_STC_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_STC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
+ /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int CRd = BITS (12, 15);
+ int Rn = BITS (16, 19);
+ int imm8 = BITS (0, 7);
+ int P = BIT(24);
+ int U = BIT(23);
+ int D = BIT(22);
+ int W = BIT(21);
+
+ /* TODO check access permission */
+
+ /* VSTM */
+ if ( (P|U|D|W) == 0 ) {
+ DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
+ exit(-1);
+ }
+ if (CoProc == 10 || CoProc == 11) {
+#if 1
+ if (P == 0 && U == 0 && W == 0) {
+ DEBUG("VSTM Related encodings\n");
+ exit(-1);
+ }
+ if (P == U && W == 1) {
+ DEBUG("UNDEFINED\n");
+ exit(-1);
+ }
+#endif
+
+#define VFP_STC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_STC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
+ instr, CoProc, CRd, Rn, imm8, P, U, D, W);
+
+ return ARMul_CANT;
}
unsigned
-VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value)
+VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value)
{
- /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int CRd = BITS (12, 15);
- int Rn = BITS (16, 19);
- int imm8 = BITS (0, 7);
- int P = BIT(24);
- int U = BIT(23);
- int D = BIT(22);
- int W = BIT(21);
-
- /* TODO check access permission */
-
- if ( (P|U|D|W) == 0 )
- {
- DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1);
- }
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_LDC_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_LDC_TRANS
- }
- DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
- instr, CoProc, CRd, Rn, imm8, P, U, D, W);
-
- return ARMul_CANT;
+ /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int CRd = BITS (12, 15);
+ int Rn = BITS (16, 19);
+ int imm8 = BITS (0, 7);
+ int P = BIT(24);
+ int U = BIT(23);
+ int D = BIT(22);
+ int W = BIT(21);
+
+ /* TODO check access permission */
+
+ if ( (P|U|D|W) == 0 ) {
+ DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
+ exit(-1);
+ }
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_LDC_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_LDC_TRANS
+ }
+ DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
+ instr, CoProc, CRd, Rn, imm8, P, U, D, W);
+
+ return ARMul_CANT;
}
unsigned
-VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
+VFPCDP (ARMul_State * state, unsigned type, u32 instr)
{
- /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
- int CoProc = BITS (8, 11); /* 10 or 11 */
- int OPC_1 = BITS (20, 23);
- int CRd = BITS (12, 15);
- int CRn = BITS (16, 19);
- int CRm = BITS (0, 3);
- int OPC_2 = BITS (5, 7);
-
- /* TODO check access permission */
-
- /* CRn/opc1 CRm/opc2 */
-
- if (CoProc == 10 || CoProc == 11)
- {
- #define VFP_CDP_TRANS
- #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
- #undef VFP_CDP_TRANS
-
- int exceptions = 0;
- if (CoProc == 10)
- exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
- else
- exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
-
- vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
-
- return ARMul_DONE;
- }
- DEBUG_LOG(ARM11, "Can't identify %x\n", instr);
- return ARMul_CANT;
+ /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
+ int CoProc = BITS (8, 11); /* 10 or 11 */
+ int OPC_1 = BITS (20, 23);
+ int CRd = BITS (12, 15);
+ int CRn = BITS (16, 19);
+ int CRm = BITS (0, 3);
+ int OPC_2 = BITS (5, 7);
+
+ //ichfly
+ /*if ((instr & 0x0FBF0FD0) == 0x0EB70AC0) //vcvt.f64.f32 d8, s16 (s is bit 0-3 and LSB bit 22) (d is bit 12 - 15 MSB is Bit 6)
+ {
+ struct vfp_double vdd;
+ struct vfp_single vsd;
+ int dn = BITS(12, 15) + (BIT(22) << 4);
+ int sd = (BITS(0, 3) << 1) + BIT(5);
+ s32 n = vfp_get_float(state, sd);
+ vfp_single_unpack(&vsd, n);
+ if (vsd.exponent & 0x80)
+ {
+ vdd.exponent = (vsd.exponent&~0x80) | 0x400;
+ }
+ else
+ {
+ vdd.exponent = vsd.exponent | 0x380;
+ }
+ vdd.sign = vsd.sign;
+ vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand
+ vfp_put_double(state, vfp_double_pack(&vdd), dn);
+ return ARMul_DONE;
+ }
+ if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6
+ {
+ struct vfp_double vdd;
+ struct vfp_single vsd;
+ int sd = BITS(0, 3) + (BIT(5) << 4);
+ int dn = (BITS(12, 15) << 1) + BIT(22);
+ vfp_double_unpack(&vdd, vfp_get_double(state, sd));
+ if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert
+ {
+ vsd.exponent = (vdd.exponent) | 0x80;
+ }
+ else
+ {
+ vsd.exponent = vdd.exponent & ~0x80;
+ }
+ vsd.exponent &= 0xFF;
+ // vsd.exponent = vdd.exponent >> 3;
+ vsd.sign = vdd.sign;
+ vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000;
+ vfp_put_float(state, vfp_single_pack(&vsd), dn);
+ return ARMul_DONE;
+ }*/
+
+ /* TODO check access permission */
+
+ /* CRn/opc1 CRm/opc2 */
+
+ if (CoProc == 10 || CoProc == 11) {
+#define VFP_CDP_TRANS
+#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
+#undef VFP_CDP_TRANS
+
+ int exceptions = 0;
+ if (CoProc == 10)
+ exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+ else
+ exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+
+ vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
+
+ return ARMul_DONE;
+ }
+ DEBUG("Can't identify %x\n", instr);
+ return ARMul_CANT;
}
@@ -301,29 +341,29 @@ VFPCDP (ARMul_State * state, unsigned type, ARMword instr)
/* Miscellaneous functions */
int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
{
- DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
- return state->ExtReg[reg];
+ DEBUG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]);
+ return state->ExtReg[reg];
}
void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg)
{
- DBG("VFP put float: s%d <= [%08x]\n", reg, val);
- state->ExtReg[reg] = val;
+ DEBUG("VFP put float: s%d <= [%08x]\n", reg, val);
+ state->ExtReg[reg] = val;
}
uint64_t vfp_get_double(arm_core_t* state, unsigned int reg)
{
- uint64_t result;
- result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
- DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
- return result;
+ uint64_t result;
+ result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2];
+ DEBUG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result);
+ return result;
}
void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
{
- DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
- state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
- state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
+ DEBUG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff));
+ state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff);
+ state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
}
@@ -333,25 +373,25 @@ void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
*/
void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr)
{
- int si_code = 0;
+ int si_code = 0;
- vfpdebug("VFP: raising exceptions %08x\n", exceptions);
+ vfpdebug("VFP: raising exceptions %08x\n", exceptions);
- if (exceptions == VFP_EXCEPTION_ERROR) {
- DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst);
- exit(-1);
- return;
- }
+ if (exceptions == VFP_EXCEPTION_ERROR) {
+ DEBUG("unhandled bounce %x\n", inst);
+ exit(-1);
+ return;
+ }
- /*
- * If any of the status flags are set, update the FPSCR.
- * Comparison instructions always return at least one of
- * these flags set.
- */
- if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
- fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
+ /*
+ * If any of the status flags are set, update the FPSCR.
+ * Comparison instructions always return at least one of
+ * these flags set.
+ */
+ if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
+ fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V);
- fpscr |= exceptions;
+ fpscr |= exceptions;
- state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
+ state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr;
}
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index ed627d41..7256701f 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -88,21 +88,21 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
/* MRC */
-inline void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value);
-inline void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value);
-inline void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2);
-inline void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
-inline void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
+void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value);
+void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value);
+void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2);
+void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
+void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm);
/* MCR */
-inline void VMSR(ARMul_State * state, ARMword reg, ARMword Rt);
+void VMSR(ARMul_State * state, ARMword reg, ARMword Rt);
/* STC */
-inline int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value);
-inline int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value);
-inline int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value);
+int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value);
+int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value);
+int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value);
/* LDC */
-inline int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value);
-inline int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value);
-inline int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value);
+int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value);
+int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value);
+int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value);
#ifdef __cplusplus
}
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index 5076e59f..b1949603 100644
--- a/src/core/arm/skyeye_common/vfp/vfp_helper.h
+++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h
@@ -44,7 +44,7 @@
#define pr_info //printf
#define pr_debug //printf
-static u32 vfp_fls(int x);
+static u32 fls(ARMword x);
#define do_div(n, base) {n/=base;}
/* From vfpinstr.h */
@@ -502,7 +502,7 @@ struct op {
u32 flags;
};
-static u32 vfp_fls(int x)
+static u32 fls(ARMword x)
{
int r = 32;
@@ -532,4 +532,9 @@ static u32 vfp_fls(int x)
}
+u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func);
+u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr);
+u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr);
+u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr);
+
#endif
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
index 13411ad8..765c1f6b 100644
--- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
@@ -56,163 +56,291 @@
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
static struct vfp_double vfp_double_default_qnan = {
- //.exponent = 2047,
- //.sign = 0,
- //.significand = VFP_DOUBLE_SIGNIFICAND_QNAN,
+ 2047,
+ 0,
+ VFP_DOUBLE_SIGNIFICAND_QNAN,
};
static void vfp_double_dump(const char *str, struct vfp_double *d)
{
- pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
- str, d->sign != 0, d->exponent, d->significand);
+ pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n",
+ str, d->sign != 0, d->exponent, d->significand);
}
static void vfp_double_normalise_denormal(struct vfp_double *vd)
{
- int bits = 31 - vfp_fls(vd->significand >> 32);
- if (bits == 31)
- bits = 63 - vfp_fls(vd->significand);
+ int bits = 31 - fls((ARMword)(vd->significand >> 32));
+ if (bits == 31)
+ bits = 63 - fls((ARMword)vd->significand);
- vfp_double_dump("normalise_denormal: in", vd);
+ vfp_double_dump("normalise_denormal: in", vd);
- if (bits) {
- vd->exponent -= bits - 1;
- vd->significand <<= bits;
- }
+ if (bits) {
+ vd->exponent -= bits - 1;
+ vd->significand <<= bits;
+ }
- vfp_double_dump("normalise_denormal: out", vd);
+ vfp_double_dump("normalise_denormal: out", vd);
}
-u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
+u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
{
- u64 significand, incr;
- int exponent, shift, underflow;
- u32 rmode;
-
- vfp_double_dump("pack: in", vd);
-
- /*
- * Infinities and NaNs are a special case.
- */
- if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
- goto pack;
-
- /*
- * Special-case zero.
- */
- if (vd->significand == 0) {
- vd->exponent = 0;
- goto pack;
- }
-
- exponent = vd->exponent;
- significand = vd->significand;
-
- shift = 32 - vfp_fls(significand >> 32);
- if (shift == 32)
- shift = 64 - vfp_fls(significand);
- if (shift) {
- exponent -= shift;
- significand <<= shift;
- }
+ u64 significand, incr;
+ int exponent, shift, underflow;
+ u32 rmode;
+
+ vfp_double_dump("pack: in", vd);
+
+ /*
+ * Infinities and NaNs are a special case.
+ */
+ if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
+ goto pack;
+
+ /*
+ * Special-case zero.
+ */
+ if (vd->significand == 0) {
+ vd->exponent = 0;
+ goto pack;
+ }
+
+ exponent = vd->exponent;
+ significand = vd->significand;
+
+ shift = 32 - fls((ARMword)(significand >> 32));
+ if (shift == 32)
+ shift = 64 - fls((ARMword)significand);
+ if (shift) {
+ exponent -= shift;
+ significand <<= shift;
+ }
#if 1
- vd->exponent = exponent;
- vd->significand = significand;
- vfp_double_dump("pack: normalised", vd);
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: normalised", vd);
#endif
- /*
- * Tiny number?
- */
- underflow = exponent < 0;
- if (underflow) {
- significand = vfp_shiftright64jamming(significand, -exponent);
- exponent = 0;
+ /*
+ * Tiny number?
+ */
+ underflow = exponent < 0;
+ if (underflow) {
+ significand = vfp_shiftright64jamming(significand, -exponent);
+ exponent = 0;
#if 1
- vd->exponent = exponent;
- vd->significand = significand;
- vfp_double_dump("pack: tiny number", vd);
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: tiny number", vd);
#endif
- if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
- underflow = 0;
- }
-
- /*
- * Select rounding increment.
- */
- incr = 0;
- rmode = fpscr & FPSCR_RMODE_MASK;
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 1ULL << VFP_DOUBLE_LOW_BITS;
- if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
- incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
-
- pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
-
- /*
- * Is our rounding going to overflow?
- */
- if ((significand + incr) < significand) {
- exponent += 1;
- significand = (significand >> 1) | (significand & 1);
- incr >>= 1;
+ if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
+ underflow = 0;
+ }
+
+ /*
+ * Select rounding increment.
+ */
+ incr = 0;
+ rmode = fpscr & FPSCR_RMODE_MASK;
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 1ULL << VFP_DOUBLE_LOW_BITS;
+ if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
+ incr -= 1;
+ }
+ else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ }
+ else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
+ incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
+
+ pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
+
+ /*
+ * Is our rounding going to overflow?
+ */
+ if ((significand + incr) < significand) {
+ exponent += 1;
+ significand = (significand >> 1) | (significand & 1);
+ incr >>= 1;
#if 1
- vd->exponent = exponent;
- vd->significand = significand;
- vfp_double_dump("pack: overflow", vd);
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: overflow", vd);
#endif
- }
-
- /*
- * If any of the low bits (which will be shifted out of the
- * number) are non-zero, the result is inexact.
- */
- if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
- exceptions |= FPSCR_IXC;
-
- /*
- * Do our rounding.
- */
- significand += incr;
-
- /*
- * Infinity?
- */
- if (exponent >= 2046) {
- exceptions |= FPSCR_OFC | FPSCR_IXC;
- if (incr == 0) {
- vd->exponent = 2045;
- vd->significand = 0x7fffffffffffffffULL;
- } else {
- vd->exponent = 2047; /* infinity */
- vd->significand = 0;
- }
- } else {
- if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
- exponent = 0;
- if (exponent || significand > 0x8000000000000000ULL)
- underflow = 0;
- if (underflow)
- exceptions |= FPSCR_UFC;
- vd->exponent = exponent;
- vd->significand = significand >> 1;
- }
-
+ }
+
+ /*
+ * If any of the low bits (which will be shifted out of the
+ * number) are non-zero, the result is inexact.
+ */
+ if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
+ exceptions |= FPSCR_IXC;
+
+ /*
+ * Do our rounding.
+ */
+ significand += incr;
+
+ /*
+ * Infinity?
+ */
+ if (exponent >= 2046) {
+ exceptions |= FPSCR_OFC | FPSCR_IXC;
+ if (incr == 0) {
+ vd->exponent = 2045;
+ vd->significand = 0x7fffffffffffffffULL;
+ }
+ else {
+ vd->exponent = 2047; /* infinity */
+ vd->significand = 0;
+ }
+ }
+ else {
+ if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
+ exponent = 0;
+ if (exponent || significand > 0x8000000000000000ULL)
+ underflow = 0;
+ if (underflow)
+ exceptions |= FPSCR_UFC;
+ vd->exponent = exponent;
+ vd->significand = significand >> 1;
+ }
pack:
- vfp_double_dump("pack: final", vd);
- {
- s64 d = vfp_double_pack(vd);
- pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func,
- dd, d, exceptions);
- vfp_put_double(state, d, dd);
- }
- return exceptions;
+ return 0;
+}
+
+u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func)
+{
+ u64 significand, incr;
+ int exponent, shift, underflow;
+ u32 rmode;
+
+ vfp_double_dump("pack: in", vd);
+
+ /*
+ * Infinities and NaNs are a special case.
+ */
+ if (vd->exponent == 2047 && (vd->significand == 0 || exceptions))
+ goto pack;
+
+ /*
+ * Special-case zero.
+ */
+ if (vd->significand == 0) {
+ vd->exponent = 0;
+ goto pack;
+ }
+
+ exponent = vd->exponent;
+ significand = vd->significand;
+
+ shift = 32 - fls((ARMword)(significand >> 32));
+ if (shift == 32)
+ shift = 64 - fls((ARMword)significand);
+ if (shift) {
+ exponent -= shift;
+ significand <<= shift;
+ }
+
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: normalised", vd);
+#endif
+
+ /*
+ * Tiny number?
+ */
+ underflow = exponent < 0;
+ if (underflow) {
+ significand = vfp_shiftright64jamming(significand, -exponent);
+ exponent = 0;
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: tiny number", vd);
+#endif
+ if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1)))
+ underflow = 0;
+ }
+
+ /*
+ * Select rounding increment.
+ */
+ incr = 0;
+ rmode = fpscr & FPSCR_RMODE_MASK;
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 1ULL << VFP_DOUBLE_LOW_BITS;
+ if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0))
+ incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1;
+
+ pr_debug("VFP: rounding increment = 0x%08llx\n", incr);
+
+ /*
+ * Is our rounding going to overflow?
+ */
+ if ((significand + incr) < significand) {
+ exponent += 1;
+ significand = (significand >> 1) | (significand & 1);
+ incr >>= 1;
+#if 1
+ vd->exponent = exponent;
+ vd->significand = significand;
+ vfp_double_dump("pack: overflow", vd);
+#endif
+ }
+
+ /*
+ * If any of the low bits (which will be shifted out of the
+ * number) are non-zero, the result is inexact.
+ */
+ if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1))
+ exceptions |= FPSCR_IXC;
+
+ /*
+ * Do our rounding.
+ */
+ significand += incr;
+
+ /*
+ * Infinity?
+ */
+ if (exponent >= 2046) {
+ exceptions |= FPSCR_OFC | FPSCR_IXC;
+ if (incr == 0) {
+ vd->exponent = 2045;
+ vd->significand = 0x7fffffffffffffffULL;
+ } else {
+ vd->exponent = 2047; /* infinity */
+ vd->significand = 0;
+ }
+ } else {
+ if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0)
+ exponent = 0;
+ if (exponent || significand > 0x8000000000000000ULL)
+ underflow = 0;
+ if (underflow)
+ exceptions |= FPSCR_UFC;
+ vd->exponent = exponent;
+ vd->significand = significand >> 1;
+ }
+
+pack:
+ vfp_double_dump("pack: final", vd);
+ {
+ s64 d = vfp_double_pack(vd);
+ pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func,
+ dd, d, exceptions);
+ vfp_put_double(state, d, dd);
+ }
+ return exceptions;
}
/*
@@ -221,43 +349,43 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd,
*/
static u32
vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
- struct vfp_double *vdm, u32 fpscr)
+ struct vfp_double *vdm, u32 fpscr)
{
- struct vfp_double *nan;
- int tn, tm = 0;
-
- tn = vfp_double_type(vdn);
-
- if (vdm)
- tm = vfp_double_type(vdm);
-
- if (fpscr & FPSCR_DEFAULT_NAN)
- /*
- * Default NaN mode - always returns a quiet NaN
- */
- nan = &vfp_double_default_qnan;
- else {
- /*
- * Contemporary mode - select the first signalling
- * NAN, or if neither are signalling, the first
- * quiet NAN.
- */
- if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
- nan = vdn;
- else
- nan = vdm;
- /*
- * Make the NaN quiet.
- */
- nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
- }
-
- *vdd = *nan;
-
- /*
- * If one was a signalling NAN, raise invalid operation.
- */
- return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
+ struct vfp_double *nan;
+ int tn, tm = 0;
+
+ tn = vfp_double_type(vdn);
+
+ if (vdm)
+ tm = vfp_double_type(vdm);
+
+ if (fpscr & FPSCR_DEFAULT_NAN)
+ /*
+ * Default NaN mode - always returns a quiet NaN
+ */
+ nan = &vfp_double_default_qnan;
+ else {
+ /*
+ * Contemporary mode - select the first signalling
+ * NAN, or if neither are signalling, the first
+ * quiet NAN.
+ */
+ if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
+ nan = vdn;
+ else
+ nan = vdm;
+ /*
+ * Make the NaN quiet.
+ */
+ nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
+ }
+
+ *vdd = *nan;
+
+ /*
+ * If one was a signalling NAN, raise invalid operation.
+ */
+ return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
}
/*
@@ -265,108 +393,108 @@ vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn,
*/
static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd);
- return 0;
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd);
+ return 0;
}
static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- vfp_put_double(state, vfp_get_double(state, dm), dd);
- return 0;
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_put_double(state, vfp_get_double(state, dm), dd);
+ return 0;
}
static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd);
- return 0;
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd);
+ return 0;
}
static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- struct vfp_double vdm, vdd, *vdp;
- int ret, tm;
-
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- tm = vfp_double_type(&vdm);
- if (tm & (VFP_NAN|VFP_INFINITY)) {
- vdp = &vdd;
-
- if (tm & VFP_NAN)
- ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
- else if (vdm.sign == 0) {
- sqrt_copy:
- vdp = &vdm;
- ret = 0;
- } else {
- sqrt_invalid:
- vdp = &vfp_double_default_qnan;
- ret = FPSCR_IOC;
- }
- vfp_put_double(state, vfp_double_pack(vdp), dd);
- return ret;
- }
-
- /*
- * sqrt(+/- 0) == +/- 0
- */
- if (tm & VFP_ZERO)
- goto sqrt_copy;
-
- /*
- * Normalise a denormalised number
- */
- if (tm & VFP_DENORMAL)
- vfp_double_normalise_denormal(&vdm);
-
- /*
- * sqrt(<0) = invalid
- */
- if (vdm.sign)
- goto sqrt_invalid;
-
- vfp_double_dump("sqrt", &vdm);
-
- /*
- * Estimate the square root.
- */
- vdd.sign = 0;
- vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
- vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
-
- vfp_double_dump("sqrt estimate1", &vdd);
-
- vdm.significand >>= 1 + (vdm.exponent & 1);
- vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
-
- vfp_double_dump("sqrt estimate2", &vdd);
-
- /*
- * And now adjust.
- */
- if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
- if (vdd.significand < 2) {
- vdd.significand = ~0ULL;
- } else {
- u64 termh, terml, remh, reml;
- vdm.significand <<= 2;
- mul64to128(&termh, &terml, vdd.significand, vdd.significand);
- sub128(&remh, &reml, vdm.significand, 0, termh, terml);
- while ((s64)remh < 0) {
- vdd.significand -= 1;
- shift64left(&termh, &terml, vdd.significand);
- terml |= 1;
- add128(&remh, &reml, remh, reml, termh, terml);
- }
- vdd.significand |= (remh | reml) != 0;
- }
- }
- vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
-
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt");
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double vdm, vdd, *vdp;
+ int ret, tm;
+
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ tm = vfp_double_type(&vdm);
+ if (tm & (VFP_NAN|VFP_INFINITY)) {
+ vdp = &vdd;
+
+ if (tm & VFP_NAN)
+ ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr);
+ else if (vdm.sign == 0) {
+sqrt_copy:
+ vdp = &vdm;
+ ret = 0;
+ } else {
+sqrt_invalid:
+ vdp = &vfp_double_default_qnan;
+ ret = FPSCR_IOC;
+ }
+ vfp_put_double(state, vfp_double_pack(vdp), dd);
+ return ret;
+ }
+
+ /*
+ * sqrt(+/- 0) == +/- 0
+ */
+ if (tm & VFP_ZERO)
+ goto sqrt_copy;
+
+ /*
+ * Normalise a denormalised number
+ */
+ if (tm & VFP_DENORMAL)
+ vfp_double_normalise_denormal(&vdm);
+
+ /*
+ * sqrt(<0) = invalid
+ */
+ if (vdm.sign)
+ goto sqrt_invalid;
+
+ vfp_double_dump("sqrt", &vdm);
+
+ /*
+ * Estimate the square root.
+ */
+ vdd.sign = 0;
+ vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023;
+ vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31;
+
+ vfp_double_dump("sqrt estimate1", &vdd);
+
+ vdm.significand >>= 1 + (vdm.exponent & 1);
+ vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand);
+
+ vfp_double_dump("sqrt estimate2", &vdd);
+
+ /*
+ * And now adjust.
+ */
+ if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) {
+ if (vdd.significand < 2) {
+ vdd.significand = ~0ULL;
+ } else {
+ u64 termh, terml, remh, reml;
+ vdm.significand <<= 2;
+ mul64to128(&termh, &terml, vdd.significand, vdd.significand);
+ sub128(&remh, &reml, vdm.significand, 0, termh, terml);
+ while ((s64)remh < 0) {
+ vdd.significand -= 1;
+ shift64left(&termh, &terml, vdd.significand);
+ terml |= 1;
+ add128(&remh, &reml, remh, reml, termh, terml);
+ }
+ vdd.significand |= (remh | reml) != 0;
+ }
+ }
+ vdd.significand = vfp_shiftright64jamming(vdd.significand, 1);
+
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt");
}
/*
@@ -377,319 +505,362 @@ static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32
*/
static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr)
{
- s64 d, m;
- u32 ret = 0;
-
- pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr);
- m = vfp_get_double(state, dm);
- if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
- ret |= FPSCR_C | FPSCR_V;
- if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
- /*
- * Signalling NaN, or signalling on quiet NaN
- */
- ret |= FPSCR_IOC;
- }
-
- d = vfp_get_double(state, dd);
- if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
- ret |= FPSCR_C | FPSCR_V;
- if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
- /*
- * Signalling NaN, or signalling on quiet NaN
- */
- ret |= FPSCR_IOC;
- }
-
- if (ret == 0) {
- //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
- if (d == m || vfp_double_packed_abs(d | m) == 0) {
- /*
- * equal
- */
- ret |= FPSCR_Z | FPSCR_C;
- //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
- } else if (vfp_double_packed_sign(d ^ m)) {
- /*
- * different signs
- */
- if (vfp_double_packed_sign(d))
- /*
- * d is negative, so d < m
- */
- ret |= FPSCR_N;
- else
- /*
- * d is positive, so d > m
- */
- ret |= FPSCR_C;
- } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
- /*
- * d < m
- */
- ret |= FPSCR_N;
- } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
- /*
- * d > m
- */
- ret |= FPSCR_C;
- }
- }
- pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret);
-
- return ret;
+ s64 d, m;
+ u32 ret = 0;
+
+ pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr);
+ m = vfp_get_double(state, dm);
+ if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) {
+ ret |= FPSCR_C | FPSCR_V;
+ if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
+ /*
+ * Signalling NaN, or signalling on quiet NaN
+ */
+ ret |= FPSCR_IOC;
+ }
+
+ d = vfp_get_double(state, dd);
+ if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) {
+ ret |= FPSCR_C | FPSCR_V;
+ if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1))))
+ /*
+ * Signalling NaN, or signalling on quiet NaN
+ */
+ ret |= FPSCR_IOC;
+ }
+
+ if (ret == 0) {
+ //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m);
+ if (d == m || vfp_double_packed_abs(d | m) == 0) {
+ /*
+ * equal
+ */
+ ret |= FPSCR_Z | FPSCR_C;
+ //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret);
+ } else if (vfp_double_packed_sign(d ^ m)) {
+ /*
+ * different signs
+ */
+ if (vfp_double_packed_sign(d))
+ /*
+ * d is negative, so d < m
+ */
+ ret |= FPSCR_N;
+ else
+ /*
+ * d is positive, so d > m
+ */
+ ret |= FPSCR_C;
+ } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) {
+ /*
+ * d < m
+ */
+ ret |= FPSCR_N;
+ } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) {
+ /*
+ * d > m
+ */
+ ret |= FPSCR_C;
+ }
+ }
+ pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret);
+
+ return ret;
}
static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_compare(state, dd, 0, dm, fpscr);
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_compare(state, dd, 0, dm, fpscr);
}
static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_compare(state, dd, 1, dm, fpscr);
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_compare(state, dd, 1, dm, fpscr);
}
static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr);
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr);
}
static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr);
+}
+
+u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr) //ichfly for internal use only
+{
+ struct vfp_single vsd;
+ int tm;
+ u32 exceptions = 0;
+
+ pr_debug("In %s\n", __FUNCTION__);
+
+ tm = vfp_double_type(dm);
+
+ /*
+ * If we have a signalling NaN, signal invalid operation.
+ */
+ if (tm == VFP_SNAN)
+ exceptions = FPSCR_IOC;
+
+ if (tm & VFP_DENORMAL)
+ vfp_double_normalise_denormal(dm);
+
+ vsd.sign = dm->sign;
+ vsd.significand = vfp_hi64to32jamming(dm->significand);
+
+ /*
+ * If we have an infinity or a NaN, the exponent must be 255
+ */
+ if (tm & (VFP_INFINITY | VFP_NAN)) {
+ vsd.exponent = 255;
+ if (tm == VFP_QNAN)
+ vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
+ goto pack_nan;
+ }
+ else if (tm & VFP_ZERO)
+ vsd.exponent = 0;
+ else
+ vsd.exponent = dm->exponent - (1023 - 127);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
+
+pack_nan:
+ vfp_put_float(state, vfp_single_pack(&vsd), sd);
+ return exceptions;
}
static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
{
- struct vfp_double vdm;
- struct vfp_single vsd;
- int tm;
- u32 exceptions = 0;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
-
- tm = vfp_double_type(&vdm);
-
- /*
- * If we have a signalling NaN, signal invalid operation.
- */
- if (tm == VFP_SNAN)
- exceptions = FPSCR_IOC;
-
- if (tm & VFP_DENORMAL)
- vfp_double_normalise_denormal(&vdm);
-
- vsd.sign = vdm.sign;
- vsd.significand = vfp_hi64to32jamming(vdm.significand);
-
- /*
- * If we have an infinity or a NaN, the exponent must be 255
- */
- if (tm & (VFP_INFINITY|VFP_NAN)) {
- vsd.exponent = 255;
- if (tm == VFP_QNAN)
- vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
- goto pack_nan;
- } else if (tm & VFP_ZERO)
- vsd.exponent = 0;
- else
- vsd.exponent = vdm.exponent - (1023 - 127);
-
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
-
- pack_nan:
- vfp_put_float(state, vfp_single_pack(&vsd), sd);
- return exceptions;
+ struct vfp_double vdm;
+ struct vfp_single vsd;
+ int tm;
+ u32 exceptions = 0;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+
+ tm = vfp_double_type(&vdm);
+
+ /*
+ * If we have a signalling NaN, signal invalid operation.
+ */
+ if (tm == VFP_SNAN)
+ exceptions = FPSCR_IOC;
+
+ if (tm & VFP_DENORMAL)
+ vfp_double_normalise_denormal(&vdm);
+
+ vsd.sign = vdm.sign;
+ vsd.significand = vfp_hi64to32jamming(vdm.significand);
+
+ /*
+ * If we have an infinity or a NaN, the exponent must be 255
+ */
+ if (tm & (VFP_INFINITY|VFP_NAN)) {
+ vsd.exponent = 255;
+ if (tm == VFP_QNAN)
+ vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
+ goto pack_nan;
+ } else if (tm & VFP_ZERO)
+ vsd.exponent = 0;
+ else
+ vsd.exponent = vdm.exponent - (1023 - 127);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts");
+
+pack_nan:
+ vfp_put_float(state, vfp_single_pack(&vsd), sd);
+ return exceptions;
}
static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- struct vfp_double vdm;
- u32 m = vfp_get_float(state, dm);
+ struct vfp_double vdm;
+ u32 m = vfp_get_float(state, dm);
- pr_debug("In %s\n", __FUNCTION__);
- vdm.sign = 0;
- vdm.exponent = 1023 + 63 - 1;
- vdm.significand = (u64)m;
+ pr_debug("In %s\n", __FUNCTION__);
+ vdm.sign = 0;
+ vdm.exponent = 1023 + 63 - 1;
+ vdm.significand = (u64)m;
- return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito");
+ return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito");
}
static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- struct vfp_double vdm;
- u32 m = vfp_get_float(state, dm);
+ struct vfp_double vdm;
+ u32 m = vfp_get_float(state, dm);
- pr_debug("In %s\n", __FUNCTION__);
- vdm.sign = (m & 0x80000000) >> 16;
- vdm.exponent = 1023 + 63 - 1;
- vdm.significand = vdm.sign ? -m : m;
+ pr_debug("In %s\n", __FUNCTION__);
+ vdm.sign = (m & 0x80000000) >> 16;
+ vdm.exponent = 1023 + 63 - 1;
+ vdm.significand = vdm.sign ? -m : m;
- return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito");
+ return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito");
}
static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
{
- struct vfp_double vdm;
- u32 d, exceptions = 0;
- int rmode = fpscr & FPSCR_RMODE_MASK;
- int tm;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
-
- /*
- * Do we have a denormalised number?
- */
- tm = vfp_double_type(&vdm);
- if (tm & VFP_DENORMAL)
- exceptions |= FPSCR_IDC;
-
- if (tm & VFP_NAN)
- vdm.sign = 0;
-
- if (vdm.exponent >= 1023 + 32) {
- d = vdm.sign ? 0 : 0xffffffff;
- exceptions = FPSCR_IOC;
- } else if (vdm.exponent >= 1023 - 1) {
- int shift = 1023 + 63 - vdm.exponent;
- u64 rem, incr = 0;
-
- /*
- * 2^0 <= m < 2^32-2^8
- */
- d = (vdm.significand << 1) >> shift;
- rem = vdm.significand << (65 - shift);
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 0x8000000000000000ULL;
- if ((d & 1) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
- incr = ~0ULL;
- }
-
- if ((rem + incr) < rem) {
- if (d < 0xffffffff)
- d += 1;
- else
- exceptions |= FPSCR_IOC;
- }
-
- if (d && vdm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
- } else if (rem)
- exceptions |= FPSCR_IXC;
- } else {
- d = 0;
- if (vdm.exponent | vdm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
- d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
- }
- }
- }
-
- pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
-
- vfp_put_float(state, d, sd);
-
- return exceptions;
+ struct vfp_double vdm;
+ u32 d, exceptions = 0;
+ int rmode = fpscr & FPSCR_RMODE_MASK;
+ int tm;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+
+ /*
+ * Do we have a denormalised number?
+ */
+ tm = vfp_double_type(&vdm);
+ if (tm & VFP_DENORMAL)
+ exceptions |= FPSCR_IDC;
+
+ if (tm & VFP_NAN)
+ vdm.sign = 0;
+
+ if (vdm.exponent >= 1023 + 32) {
+ d = vdm.sign ? 0 : 0xffffffff;
+ exceptions = FPSCR_IOC;
+ } else if (vdm.exponent >= 1023 - 1) {
+ int shift = 1023 + 63 - vdm.exponent;
+ u64 rem, incr = 0;
+
+ /*
+ * 2^0 <= m < 2^32-2^8
+ */
+ d = (ARMword)((vdm.significand << 1) >> shift);
+ rem = vdm.significand << (65 - shift);
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 0x8000000000000000ULL;
+ if ((d & 1) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
+ incr = ~0ULL;
+ }
+
+ if ((rem + incr) < rem) {
+ if (d < 0xffffffff)
+ d += 1;
+ else
+ exceptions |= FPSCR_IOC;
+ }
+
+ if (d && vdm.sign) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ } else if (rem)
+ exceptions |= FPSCR_IXC;
+ } else {
+ d = 0;
+ if (vdm.exponent | vdm.significand) {
+ exceptions |= FPSCR_IXC;
+ if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
+ d = 1;
+ else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ }
+ }
+ }
+
+ pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+
+ vfp_put_float(state, d, sd);
+
+ return exceptions;
}
static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO);
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO);
}
static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr)
{
- struct vfp_double vdm;
- u32 d, exceptions = 0;
- int rmode = fpscr & FPSCR_RMODE_MASK;
- int tm;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- vfp_double_dump("VDM", &vdm);
-
- /*
- * Do we have denormalised number?
- */
- tm = vfp_double_type(&vdm);
- if (tm & VFP_DENORMAL)
- exceptions |= FPSCR_IDC;
-
- if (tm & VFP_NAN) {
- d = 0;
- exceptions |= FPSCR_IOC;
- } else if (vdm.exponent >= 1023 + 32) {
- d = 0x7fffffff;
- if (vdm.sign)
- d = ~d;
- exceptions |= FPSCR_IOC;
- } else if (vdm.exponent >= 1023 - 1) {
- int shift = 1023 + 63 - vdm.exponent; /* 58 */
- u64 rem, incr = 0;
-
- d = (vdm.significand << 1) >> shift;
- rem = vdm.significand << (65 - shift);
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 0x8000000000000000ULL;
- if ((d & 1) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
- incr = ~0ULL;
- }
-
- if ((rem + incr) < rem && d < 0xffffffff)
- d += 1;
- if (d > 0x7fffffff + (vdm.sign != 0)) {
- d = 0x7fffffff + (vdm.sign != 0);
- exceptions |= FPSCR_IOC;
- } else if (rem)
- exceptions |= FPSCR_IXC;
-
- if (vdm.sign)
- d = -d;
- } else {
- d = 0;
- if (vdm.exponent | vdm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
- d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
- d = -1;
- }
- }
-
- pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
-
- vfp_put_float(state, (s32)d, sd);
-
- return exceptions;
+ struct vfp_double vdm;
+ u32 d, exceptions = 0;
+ int rmode = fpscr & FPSCR_RMODE_MASK;
+ int tm;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ vfp_double_dump("VDM", &vdm);
+
+ /*
+ * Do we have denormalised number?
+ */
+ tm = vfp_double_type(&vdm);
+ if (tm & VFP_DENORMAL)
+ exceptions |= FPSCR_IDC;
+
+ if (tm & VFP_NAN) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ } else if (vdm.exponent >= 1023 + 32) {
+ d = 0x7fffffff;
+ if (vdm.sign)
+ d = ~d;
+ exceptions |= FPSCR_IOC;
+ } else if (vdm.exponent >= 1023 - 1) {
+ int shift = 1023 + 63 - vdm.exponent; /* 58 */
+ u64 rem, incr = 0;
+
+ d = (ARMword)((vdm.significand << 1) >> shift);
+ rem = vdm.significand << (65 - shift);
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 0x8000000000000000ULL;
+ if ((d & 1) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) {
+ incr = ~0ULL;
+ }
+
+ if ((rem + incr) < rem && d < 0xffffffff)
+ d += 1;
+ if (d > (0x7fffffff + (vdm.sign != 0))) {
+ d = (0x7fffffff + (vdm.sign != 0));
+ exceptions |= FPSCR_IOC;
+ } else if (rem)
+ exceptions |= FPSCR_IXC;
+
+ if (vdm.sign)
+ d = -d;
+ } else {
+ d = 0;
+ if (vdm.exponent | vdm.significand) {
+ exceptions |= FPSCR_IXC;
+ if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0)
+ d = 1;
+ else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign)
+ d = -1;
+ }
+ }
+
+ pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+
+ vfp_put_float(state, (s32)d, sd);
+
+ return exceptions;
}
static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO);
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO);
}
static struct op fops_ext[] = {
@@ -728,197 +899,195 @@ static struct op fops_ext[] = {
static u32
vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn,
- struct vfp_double *vdm, u32 fpscr)
+ struct vfp_double *vdm, u32 fpscr)
{
- struct vfp_double *vdp;
- u32 exceptions = 0;
- int tn, tm;
-
- tn = vfp_double_type(vdn);
- tm = vfp_double_type(vdm);
-
- if (tn & tm & VFP_INFINITY) {
- /*
- * Two infinities. Are they different signs?
- */
- if (vdn->sign ^ vdm->sign) {
- /*
- * different signs -> invalid
- */
- exceptions = FPSCR_IOC;
- vdp = &vfp_double_default_qnan;
- } else {
- /*
- * same signs -> valid
- */
- vdp = vdn;
- }
- } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
- /*
- * One infinity and one number -> infinity
- */
- vdp = vdn;
- } else {
- /*
- * 'n' is a NaN of some type
- */
- return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
- }
- *vdd = *vdp;
- return exceptions;
+ struct vfp_double *vdp;
+ u32 exceptions = 0;
+ int tn, tm;
+
+ tn = vfp_double_type(vdn);
+ tm = vfp_double_type(vdm);
+
+ if (tn & tm & VFP_INFINITY) {
+ /*
+ * Two infinities. Are they different signs?
+ */
+ if (vdn->sign ^ vdm->sign) {
+ /*
+ * different signs -> invalid
+ */
+ exceptions = FPSCR_IOC;
+ vdp = &vfp_double_default_qnan;
+ } else {
+ /*
+ * same signs -> valid
+ */
+ vdp = vdn;
+ }
+ } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
+ /*
+ * One infinity and one number -> infinity
+ */
+ vdp = vdn;
+ } else {
+ /*
+ * 'n' is a NaN of some type
+ */
+ return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
+ }
+ *vdd = *vdp;
+ return exceptions;
}
-static u32
-vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,
- struct vfp_double *vdm, u32 fpscr)
+u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_double *vdm, u32 fpscr)
{
- u32 exp_diff;
- u64 m_sig;
-
- if (vdn->significand & (1ULL << 63) ||
- vdm->significand & (1ULL << 63)) {
- pr_info("VFP: bad FP values\n");
- vfp_double_dump("VDN", vdn);
- vfp_double_dump("VDM", vdm);
- }
-
- /*
- * Ensure that 'n' is the largest magnitude number. Note that
- * if 'n' and 'm' have equal exponents, we do not swap them.
- * This ensures that NaN propagation works correctly.
- */
- if (vdn->exponent < vdm->exponent) {
- struct vfp_double *t = vdn;
- vdn = vdm;
- vdm = t;
- }
-
- /*
- * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
- * infinity or a NaN here.
- */
- if (vdn->exponent == 2047)
- return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
-
- /*
- * We have two proper numbers, where 'vdn' is the larger magnitude.
- *
- * Copy 'n' to 'd' before doing the arithmetic.
- */
- *vdd = *vdn;
-
- /*
- * Align 'm' with the result.
- */
- exp_diff = vdn->exponent - vdm->exponent;
- m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
-
- /*
- * If the signs are different, we are really subtracting.
- */
- if (vdn->sign ^ vdm->sign) {
- m_sig = vdn->significand - m_sig;
- if ((s64)m_sig < 0) {
- vdd->sign = vfp_sign_negate(vdd->sign);
- m_sig = -m_sig;
- } else if (m_sig == 0) {
- vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
- FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
- }
- } else {
- m_sig += vdn->significand;
- }
- vdd->significand = m_sig;
-
- return 0;
+ u32 exp_diff;
+ u64 m_sig;
+
+ if (vdn->significand & (1ULL << 63) ||
+ vdm->significand & (1ULL << 63)) {
+ pr_info("VFP: bad FP values in %s\n", __func__);
+ vfp_double_dump("VDN", vdn);
+ vfp_double_dump("VDM", vdm);
+ }
+
+ /*
+ * Ensure that 'n' is the largest magnitude number. Note that
+ * if 'n' and 'm' have equal exponents, we do not swap them.
+ * This ensures that NaN propagation works correctly.
+ */
+ if (vdn->exponent < vdm->exponent) {
+ struct vfp_double *t = vdn;
+ vdn = vdm;
+ vdm = t;
+ }
+
+ /*
+ * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
+ * infinity or a NaN here.
+ */
+ if (vdn->exponent == 2047)
+ return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr);
+
+ /*
+ * We have two proper numbers, where 'vdn' is the larger magnitude.
+ *
+ * Copy 'n' to 'd' before doing the arithmetic.
+ */
+ *vdd = *vdn;
+
+ /*
+ * Align 'm' with the result.
+ */
+ exp_diff = vdn->exponent - vdm->exponent;
+ m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff);
+
+ /*
+ * If the signs are different, we are really subtracting.
+ */
+ if (vdn->sign ^ vdm->sign) {
+ m_sig = vdn->significand - m_sig;
+ if ((s64)m_sig < 0) {
+ vdd->sign = vfp_sign_negate(vdd->sign);
+ m_sig = -m_sig;
+ } else if (m_sig == 0) {
+ vdd->sign = (fpscr & FPSCR_RMODE_MASK) ==
+ FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
+ }
+ } else {
+ m_sig += vdn->significand;
+ }
+ vdd->significand = m_sig;
+
+ return 0;
}
-static u32
+u32
vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn,
- struct vfp_double *vdm, u32 fpscr)
+ struct vfp_double *vdm, u32 fpscr)
{
- vfp_double_dump("VDN", vdn);
- vfp_double_dump("VDM", vdm);
-
- /*
- * Ensure that 'n' is the largest magnitude number. Note that
- * if 'n' and 'm' have equal exponents, we do not swap them.
- * This ensures that NaN propagation works correctly.
- */
- if (vdn->exponent < vdm->exponent) {
- struct vfp_double *t = vdn;
- vdn = vdm;
- vdm = t;
- pr_debug("VFP: swapping M <-> N\n");
- }
-
- vdd->sign = vdn->sign ^ vdm->sign;
-
- /*
- * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
- */
- if (vdn->exponent == 2047) {
- if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
- return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
- if ((vdm->exponent | vdm->significand) == 0) {
- *vdd = vfp_double_default_qnan;
- return FPSCR_IOC;
- }
- vdd->exponent = vdn->exponent;
- vdd->significand = 0;
- return 0;
- }
-
- /*
- * If 'm' is zero, the result is always zero. In this case,
- * 'n' may be zero or a number, but it doesn't matter which.
- */
- if ((vdm->exponent | vdm->significand) == 0) {
- vdd->exponent = 0;
- vdd->significand = 0;
- return 0;
- }
-
- /*
- * We add 2 to the destination exponent for the same reason
- * as the addition case - though this time we have +1 from
- * each input operand.
- */
- vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
- vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
-
- vfp_double_dump("VDD", vdd);
- return 0;
+ vfp_double_dump("VDN", vdn);
+ vfp_double_dump("VDM", vdm);
+
+ /*
+ * Ensure that 'n' is the largest magnitude number. Note that
+ * if 'n' and 'm' have equal exponents, we do not swap them.
+ * This ensures that NaN propagation works correctly.
+ */
+ if (vdn->exponent < vdm->exponent) {
+ struct vfp_double *t = vdn;
+ vdn = vdm;
+ vdm = t;
+ pr_debug("VFP: swapping M <-> N\n");
+ }
+
+ vdd->sign = vdn->sign ^ vdm->sign;
+
+ /*
+ * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
+ */
+ if (vdn->exponent == 2047) {
+ if (vdn->significand || (vdm->exponent == 2047 && vdm->significand))
+ return vfp_propagate_nan(vdd, vdn, vdm, fpscr);
+ if ((vdm->exponent | vdm->significand) == 0) {
+ *vdd = vfp_double_default_qnan;
+ return FPSCR_IOC;
+ }
+ vdd->exponent = vdn->exponent;
+ vdd->significand = 0;
+ return 0;
+ }
+
+ /*
+ * If 'm' is zero, the result is always zero. In this case,
+ * 'n' may be zero or a number, but it doesn't matter which.
+ */
+ if ((vdm->exponent | vdm->significand) == 0) {
+ vdd->exponent = 0;
+ vdd->significand = 0;
+ return 0;
+ }
+
+ /*
+ * We add 2 to the destination exponent for the same reason
+ * as the addition case - though this time we have +1 from
+ * each input operand.
+ */
+ vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2;
+ vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand);
+
+ vfp_double_dump("VDD", vdd);
+ return 0;
}
#define NEG_MULTIPLY (1 << 0)
#define NEG_SUBTRACT (1 << 1)
static u32
-vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func)
+vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, char *func)
{
- struct vfp_double vdd, vdp, vdn, vdm;
- u32 exceptions;
+ struct vfp_double vdd, vdp, vdn, vdm;
+ u32 exceptions;
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
- exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
- if (negate & NEG_MULTIPLY)
- vdp.sign = vfp_sign_negate(vdp.sign);
+ exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr);
+ if (negate & NEG_MULTIPLY)
+ vdp.sign = vfp_sign_negate(vdp.sign);
- vfp_double_unpack(&vdn, vfp_get_double(state, dd));
- if (negate & NEG_SUBTRACT)
- vdn.sign = vfp_sign_negate(vdn.sign);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dd));
+ if (negate & NEG_SUBTRACT)
+ vdn.sign = vfp_sign_negate(vdn.sign);
- exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
+ exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr);
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func);
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func);
}
/*
@@ -930,8 +1099,8 @@ vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 f
*/
static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac");
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac");
}
/*
@@ -939,8 +1108,8 @@ static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
*/
static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac");
}
/*
@@ -948,8 +1117,8 @@ static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpsc
*/
static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc");
}
/*
@@ -957,8 +1126,8 @@ static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
*/
static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- pr_debug("In %s\n", __FUNCTION__);
- return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
+ pr_debug("In %s\n", __FUNCTION__);
+ return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
}
/*
@@ -966,20 +1135,20 @@ static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpsc
*/
static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions;
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions;
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
- exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul");
+ exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul");
}
/*
@@ -987,22 +1156,22 @@ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
*/
static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions;
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions;
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
- exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
- vdd.sign = vfp_sign_negate(vdd.sign);
+ exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr);
+ vdd.sign = vfp_sign_negate(vdd.sign);
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul");
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul");
}
/*
@@ -1010,21 +1179,21 @@ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpsc
*/
static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions;
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions;
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
- exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
+ exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd");
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd");
}
/*
@@ -1032,26 +1201,26 @@ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
*/
static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions;
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions;
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- if (vdn.exponent == 0 && vdn.significand)
- vfp_double_normalise_denormal(&vdn);
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ if (vdn.exponent == 0 && vdn.significand)
+ vfp_double_normalise_denormal(&vdn);
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
- if (vdm.exponent == 0 && vdm.significand)
- vfp_double_normalise_denormal(&vdm);
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+ if (vdm.exponent == 0 && vdm.significand)
+ vfp_double_normalise_denormal(&vdm);
- /*
- * Subtraction is like addition, but with a negated operand.
- */
- vdm.sign = vfp_sign_negate(vdm.sign);
+ /*
+ * Subtraction is like addition, but with a negated operand.
+ */
+ vdm.sign = vfp_sign_negate(vdm.sign);
- exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
+ exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr);
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub");
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub");
}
/*
@@ -1059,120 +1228,120 @@ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr
*/
static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr)
{
- struct vfp_double vdd, vdn, vdm;
- u32 exceptions = 0;
- int tm, tn;
-
- pr_debug("In %s\n", __FUNCTION__);
- vfp_double_unpack(&vdn, vfp_get_double(state, dn));
- vfp_double_unpack(&vdm, vfp_get_double(state, dm));
-
- vdd.sign = vdn.sign ^ vdm.sign;
-
- tn = vfp_double_type(&vdn);
- tm = vfp_double_type(&vdm);
-
- /*
- * Is n a NAN?
- */
- if (tn & VFP_NAN)
- goto vdn_nan;
-
- /*
- * Is m a NAN?
- */
- if (tm & VFP_NAN)
- goto vdm_nan;
-
- /*
- * If n and m are infinity, the result is invalid
- * If n and m are zero, the result is invalid
- */
- if (tm & tn & (VFP_INFINITY|VFP_ZERO))
- goto invalid;
-
- /*
- * If n is infinity, the result is infinity
- */
- if (tn & VFP_INFINITY)
- goto infinity;
-
- /*
- * If m is zero, raise div0 exceptions
- */
- if (tm & VFP_ZERO)
- goto divzero;
-
- /*
- * If m is infinity, or n is zero, the result is zero
- */
- if (tm & VFP_INFINITY || tn & VFP_ZERO)
- goto zero;
-
- if (tn & VFP_DENORMAL)
- vfp_double_normalise_denormal(&vdn);
- if (tm & VFP_DENORMAL)
- vfp_double_normalise_denormal(&vdm);
-
- /*
- * Ok, we have two numbers, we can perform division.
- */
- vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
- vdm.significand <<= 1;
- if (vdm.significand <= (2 * vdn.significand)) {
- vdn.significand >>= 1;
- vdd.exponent++;
- }
- vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
- if ((vdd.significand & 0x1ff) <= 2) {
- u64 termh, terml, remh, reml;
- mul64to128(&termh, &terml, vdm.significand, vdd.significand);
- sub128(&remh, &reml, vdn.significand, 0, termh, terml);
- while ((s64)remh < 0) {
- vdd.significand -= 1;
- add128(&remh, &reml, remh, reml, 0, vdm.significand);
- }
- vdd.significand |= (reml != 0);
- }
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
-
- vdn_nan:
- exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
- pack:
- vfp_put_double(state, vfp_double_pack(&vdd), dd);
- return exceptions;
-
- vdm_nan:
- exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
- goto pack;
-
- zero:
- vdd.exponent = 0;
- vdd.significand = 0;
- goto pack;
-
- divzero:
- exceptions = FPSCR_DZC;
- infinity:
- vdd.exponent = 2047;
- vdd.significand = 0;
- goto pack;
-
- invalid:
- vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
- return FPSCR_IOC;
+ struct vfp_double vdd, vdn, vdm;
+ u32 exceptions = 0;
+ int tm, tn;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vfp_double_unpack(&vdn, vfp_get_double(state, dn));
+ vfp_double_unpack(&vdm, vfp_get_double(state, dm));
+
+ vdd.sign = vdn.sign ^ vdm.sign;
+
+ tn = vfp_double_type(&vdn);
+ tm = vfp_double_type(&vdm);
+
+ /*
+ * Is n a NAN?
+ */
+ if (tn & VFP_NAN)
+ goto vdn_nan;
+
+ /*
+ * Is m a NAN?
+ */
+ if (tm & VFP_NAN)
+ goto vdm_nan;
+
+ /*
+ * If n and m are infinity, the result is invalid
+ * If n and m are zero, the result is invalid
+ */
+ if (tm & tn & (VFP_INFINITY|VFP_ZERO))
+ goto invalid;
+
+ /*
+ * If n is infinity, the result is infinity
+ */
+ if (tn & VFP_INFINITY)
+ goto infinity;
+
+ /*
+ * If m is zero, raise div0 exceptions
+ */
+ if (tm & VFP_ZERO)
+ goto divzero;
+
+ /*
+ * If m is infinity, or n is zero, the result is zero
+ */
+ if (tm & VFP_INFINITY || tn & VFP_ZERO)
+ goto zero;
+
+ if (tn & VFP_DENORMAL)
+ vfp_double_normalise_denormal(&vdn);
+ if (tm & VFP_DENORMAL)
+ vfp_double_normalise_denormal(&vdm);
+
+ /*
+ * Ok, we have two numbers, we can perform division.
+ */
+ vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1;
+ vdm.significand <<= 1;
+ if (vdm.significand <= (2 * vdn.significand)) {
+ vdn.significand >>= 1;
+ vdd.exponent++;
+ }
+ vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand);
+ if ((vdd.significand & 0x1ff) <= 2) {
+ u64 termh, terml, remh, reml;
+ mul64to128(&termh, &terml, vdm.significand, vdd.significand);
+ sub128(&remh, &reml, vdn.significand, 0, termh, terml);
+ while ((s64)remh < 0) {
+ vdd.significand -= 1;
+ add128(&remh, &reml, remh, reml, 0, vdm.significand);
+ }
+ vdd.significand |= (reml != 0);
+ }
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv");
+
+vdn_nan:
+ exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr);
+pack:
+ vfp_put_double(state, vfp_double_pack(&vdd), dd);
+ return exceptions;
+
+vdm_nan:
+ exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr);
+ goto pack;
+
+zero:
+ vdd.exponent = 0;
+ vdd.significand = 0;
+ goto pack;
+
+divzero:
+ exceptions = FPSCR_DZC;
+infinity:
+ vdd.exponent = 2047;
+ vdd.significand = 0;
+ goto pack;
+
+invalid:
+ vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd);
+ return FPSCR_IOC;
}
static struct op fops[] = {
- { vfp_double_fmac, 0 },
- { vfp_double_fmsc, 0 },
- { vfp_double_fmul, 0 },
- { vfp_double_fadd, 0 },
- { vfp_double_fnmac, 0 },
- { vfp_double_fnmsc, 0 },
- { vfp_double_fnmul, 0 },
- { vfp_double_fsub, 0 },
- { vfp_double_fdiv, 0 },
+ { vfp_double_fmac, 0 },
+ { vfp_double_fmsc, 0 },
+ { vfp_double_fmul, 0 },
+ { vfp_double_fadd, 0 },
+ { vfp_double_fnmac, 0 },
+ { vfp_double_fnmsc, 0 },
+ { vfp_double_fnmul, 0 },
+ { vfp_double_fsub, 0 },
+ { vfp_double_fdiv, 0 },
};
#define FREG_BANK(x) ((x) & 0x0c)
@@ -1180,84 +1349,84 @@ static struct op fops[] = {
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
{
- u32 op = inst & FOP_MASK;
- u32 exceptions = 0;
- unsigned int dest;
- unsigned int dn = vfp_get_dn(inst);
- unsigned int dm;
- unsigned int vecitr, veclen, vecstride;
- struct op *fop;
-
- pr_debug("In %s\n", __FUNCTION__);
- vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
-
- fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
-
- /*
- * fcvtds takes an sN register number as destination, not dN.
- * It also always operates on scalars.
- */
- if (fop->flags & OP_SD)
- dest = vfp_get_sd(inst);
- else
- dest = vfp_get_dd(inst);
-
- /*
- * f[us]ito takes a sN operand, not a dN operand.
- */
- if (fop->flags & OP_SM)
- dm = vfp_get_sm(inst);
- else
- dm = vfp_get_dm(inst);
-
- /*
- * If destination bank is zero, vector length is always '1'.
- * ARM DDI0100F C5.1.3, C5.3.2.
- */
- if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
- veclen = 0;
- else
- veclen = fpscr & FPSCR_LENGTH_MASK;
-
- pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
- (veclen >> FPSCR_LENGTH_BIT) + 1);
-
- if (!fop->fn) {
- printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst));
- goto invalid;
- }
-
- for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
- u32 except;
- char type;
-
- type = fop->flags & OP_SD ? 's' : 'd';
- if (op == FOP_EXT)
- pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
- vecitr >> FPSCR_LENGTH_BIT,
- type, dest, dn, dm);
- else
- pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
- vecitr >> FPSCR_LENGTH_BIT,
- type, dest, dn, FOP_TO_IDX(op), dm);
-
- except = fop->fn(state, dest, dn, dm, fpscr);
- pr_debug("VFP: itr%d: exceptions=%08x\n",
- vecitr >> FPSCR_LENGTH_BIT, except);
-
- exceptions |= except;
-
- /*
- * CHECK: It appears to be undefined whether we stop when
- * we encounter an exception. We continue.
- */
- dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
- dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
- if (FREG_BANK(dm) != 0)
- dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
- }
- return exceptions;
-
- invalid:
- return ~0;
+ u32 op = inst & FOP_MASK;
+ u32 exceptions = 0;
+ unsigned int dest;
+ unsigned int dn = vfp_get_dn(inst);
+ unsigned int dm;
+ unsigned int vecitr, veclen, vecstride;
+ struct op *fop;
+
+ pr_debug("In %s\n", __FUNCTION__);
+ vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK));
+
+ fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
+
+ /*
+ * fcvtds takes an sN register number as destination, not dN.
+ * It also always operates on scalars.
+ */
+ if (fop->flags & OP_SD)
+ dest = vfp_get_sd(inst);
+ else
+ dest = vfp_get_dd(inst);
+
+ /*
+ * f[us]ito takes a sN operand, not a dN operand.
+ */
+ if (fop->flags & OP_SM)
+ dm = vfp_get_sm(inst);
+ else
+ dm = vfp_get_dm(inst);
+
+ /*
+ * If destination bank is zero, vector length is always '1'.
+ * ARM DDI0100F C5.1.3, C5.3.2.
+ */
+ if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
+ veclen = 0;
+ else
+ veclen = fpscr & FPSCR_LENGTH_MASK;
+
+ pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
+ (veclen >> FPSCR_LENGTH_BIT) + 1);
+
+ if (!fop->fn) {
+ printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst));
+ goto invalid;
+ }
+
+ for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
+ u32 except;
+ char type;
+
+ type = fop->flags & OP_SD ? 's' : 'd';
+ if (op == FOP_EXT)
+ pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
+ vecitr >> FPSCR_LENGTH_BIT,
+ type, dest, dn, dm);
+ else
+ pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
+ vecitr >> FPSCR_LENGTH_BIT,
+ type, dest, dn, FOP_TO_IDX(op), dm);
+
+ except = fop->fn(state, dest, dn, dm, fpscr);
+ pr_debug("VFP: itr%d: exceptions=%08x\n",
+ vecitr >> FPSCR_LENGTH_BIT, except);
+
+ exceptions |= except;
+
+ /*
+ * CHECK: It appears to be undefined whether we stop when
+ * we encounter an exception. We continue.
+ */
+ dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3);
+ dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3);
+ if (FREG_BANK(dm) != 0)
+ dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3);
+ }
+ return exceptions;
+
+invalid:
+ return ~0;
}
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 8bcbd4fe..07d0c1f4 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -56,167 +56,167 @@
#include "core/arm/skyeye_common/vfp/vfp.h"
static struct vfp_single vfp_single_default_qnan = {
- //.exponent = 255,
- //.sign = 0,
- //.significand = VFP_SINGLE_SIGNIFICAND_QNAN,
+ 255,
+ 0,
+ VFP_SINGLE_SIGNIFICAND_QNAN,
};
static void vfp_single_dump(const char *str, struct vfp_single *s)
{
- pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
- str, s->sign != 0, s->exponent, s->significand);
+ pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n",
+ str, s->sign != 0, s->exponent, s->significand);
}
static void vfp_single_normalise_denormal(struct vfp_single *vs)
{
- int bits = 31 - vfp_fls(vs->significand);
+ int bits = 31 - fls(vs->significand);
- vfp_single_dump("normalise_denormal: in", vs);
+ vfp_single_dump("normalise_denormal: in", vs);
- if (bits) {
- vs->exponent -= bits - 1;
- vs->significand <<= bits;
- }
+ if (bits) {
+ vs->exponent -= bits - 1;
+ vs->significand <<= bits;
+ }
- vfp_single_dump("normalise_denormal: out", vs);
+ vfp_single_dump("normalise_denormal: out", vs);
}
u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func)
{
- u32 significand, incr, rmode;
- int exponent, shift, underflow;
-
- vfp_single_dump("pack: in", vs);
-
- /*
- * Infinities and NaNs are a special case.
- */
- if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
- goto pack;
-
- /*
- * Special-case zero.
- */
- if (vs->significand == 0) {
- vs->exponent = 0;
- goto pack;
- }
-
- exponent = vs->exponent;
- significand = vs->significand;
-
- /*
- * Normalise first. Note that we shift the significand up to
- * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
- * significant bit.
- */
- shift = 32 - vfp_fls(significand);
- if (shift < 32 && shift) {
- exponent -= shift;
- significand <<= shift;
- }
+ u32 significand, incr, rmode;
+ int exponent, shift, underflow;
+
+ vfp_single_dump("pack: in", vs);
+
+ /*
+ * Infinities and NaNs are a special case.
+ */
+ if (vs->exponent == 255 && (vs->significand == 0 || exceptions))
+ goto pack;
+
+ /*
+ * Special-case zero.
+ */
+ if (vs->significand == 0) {
+ vs->exponent = 0;
+ goto pack;
+ }
+
+ exponent = vs->exponent;
+ significand = vs->significand;
+
+ /*
+ * Normalise first. Note that we shift the significand up to
+ * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least
+ * significant bit.
+ */
+ shift = 32 - fls(significand);
+ if (shift < 32 && shift) {
+ exponent -= shift;
+ significand <<= shift;
+ }
#if 1
- vs->exponent = exponent;
- vs->significand = significand;
- vfp_single_dump("pack: normalised", vs);
+ vs->exponent = exponent;
+ vs->significand = significand;
+ vfp_single_dump("pack: normalised", vs);
#endif
- /*
- * Tiny number?
- */
- underflow = exponent < 0;
- if (underflow) {
- significand = vfp_shiftright32jamming(significand, -exponent);
- exponent = 0;
+ /*
+ * Tiny number?
+ */
+ underflow = exponent < 0;
+ if (underflow) {
+ significand = vfp_shiftright32jamming(significand, -exponent);
+ exponent = 0;
#if 1
- vs->exponent = exponent;
- vs->significand = significand;
- vfp_single_dump("pack: tiny number", vs);
+ vs->exponent = exponent;
+ vs->significand = significand;
+ vfp_single_dump("pack: tiny number", vs);
#endif
- if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
- underflow = 0;
- }
-
- /*
- * Select rounding increment.
- */
- incr = 0;
- rmode = fpscr & FPSCR_RMODE_MASK;
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 1 << VFP_SINGLE_LOW_BITS;
- if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
- incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
-
- pr_debug("VFP: rounding increment = 0x%08x\n", incr);
-
- /*
- * Is our rounding going to overflow?
- */
- if ((significand + incr) < significand) {
- exponent += 1;
- significand = (significand >> 1) | (significand & 1);
- incr >>= 1;
+ if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)))
+ underflow = 0;
+ }
+
+ /*
+ * Select rounding increment.
+ */
+ incr = 0;
+ rmode = fpscr & FPSCR_RMODE_MASK;
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 1 << VFP_SINGLE_LOW_BITS;
+ if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0))
+ incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1;
+
+ pr_debug("VFP: rounding increment = 0x%08x\n", incr);
+
+ /*
+ * Is our rounding going to overflow?
+ */
+ if ((significand + incr) < significand) {
+ exponent += 1;
+ significand = (significand >> 1) | (significand & 1);
+ incr >>= 1;
#if 1
- vs->exponent = exponent;
- vs->significand = significand;
- vfp_single_dump("pack: overflow", vs);
+ vs->exponent = exponent;
+ vs->significand = significand;
+ vfp_single_dump("pack: overflow", vs);
#endif
- }
-
- /*
- * If any of the low bits (which will be shifted out of the
- * number) are non-zero, the result is inexact.
- */
- if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
- exceptions |= FPSCR_IXC;
-
- /*
- * Do our rounding.
- */
- significand += incr;
-
- /*
- * Infinity?
- */
- if (exponent >= 254) {
- exceptions |= FPSCR_OFC | FPSCR_IXC;
- if (incr == 0) {
- vs->exponent = 253;
- vs->significand = 0x7fffffff;
- } else {
- vs->exponent = 255; /* infinity */
- vs->significand = 0;
- }
- } else {
- if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
- exponent = 0;
- if (exponent || significand > 0x80000000)
- underflow = 0;
- if (underflow)
- exceptions |= FPSCR_UFC;
- vs->exponent = exponent;
- vs->significand = significand >> 1;
- }
-
- pack:
- vfp_single_dump("pack: final", vs);
- {
- s32 d = vfp_single_pack(vs);
+ }
+
+ /*
+ * If any of the low bits (which will be shifted out of the
+ * number) are non-zero, the result is inexact.
+ */
+ if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))
+ exceptions |= FPSCR_IXC;
+
+ /*
+ * Do our rounding.
+ */
+ significand += incr;
+
+ /*
+ * Infinity?
+ */
+ if (exponent >= 254) {
+ exceptions |= FPSCR_OFC | FPSCR_IXC;
+ if (incr == 0) {
+ vs->exponent = 253;
+ vs->significand = 0x7fffffff;
+ } else {
+ vs->exponent = 255; /* infinity */
+ vs->significand = 0;
+ }
+ } else {
+ if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0)
+ exponent = 0;
+ if (exponent || significand > 0x80000000)
+ underflow = 0;
+ if (underflow)
+ exceptions |= FPSCR_UFC;
+ vs->exponent = exponent;
+ vs->significand = significand >> 1;
+ }
+
+pack:
+ vfp_single_dump("pack: final", vs);
+ {
+ s32 d = vfp_single_pack(vs);
#if 1
- pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
- sd, d, exceptions);
+ pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
+ sd, d, exceptions);
#endif
- vfp_put_float(state, d, sd);
- }
+ vfp_put_float(state, d, sd);
+ }
- return exceptions;
+ return exceptions;
}
/*
@@ -225,43 +225,43 @@ u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs,
*/
static u32
vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
- struct vfp_single *vsm, u32 fpscr)
+ struct vfp_single *vsm, u32 fpscr)
{
- struct vfp_single *nan;
- int tn, tm = 0;
-
- tn = vfp_single_type(vsn);
-
- if (vsm)
- tm = vfp_single_type(vsm);
-
- if (fpscr & FPSCR_DEFAULT_NAN)
- /*
- * Default NaN mode - always returns a quiet NaN
- */
- nan = &vfp_single_default_qnan;
- else {
- /*
- * Contemporary mode - select the first signalling
- * NAN, or if neither are signalling, the first
- * quiet NAN.
- */
- if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
- nan = vsn;
- else
- nan = vsm;
- /*
- * Make the NaN quiet.
- */
- nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
- }
-
- *vsd = *nan;
-
- /*
- * If one was a signalling NAN, raise invalid operation.
- */
- return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
+ struct vfp_single *nan;
+ int tn, tm = 0;
+
+ tn = vfp_single_type(vsn);
+
+ if (vsm)
+ tm = vfp_single_type(vsm);
+
+ if (fpscr & FPSCR_DEFAULT_NAN)
+ /*
+ * Default NaN mode - always returns a quiet NaN
+ */
+ nan = &vfp_single_default_qnan;
+ else {
+ /*
+ * Contemporary mode - select the first signalling
+ * NAN, or if neither are signalling, the first
+ * quiet NAN.
+ */
+ if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN))
+ nan = vsn;
+ else
+ nan = vsm;
+ /*
+ * Make the NaN quiet.
+ */
+ nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN;
+ }
+
+ *vsd = *nan;
+
+ /*
+ * If one was a signalling NAN, raise invalid operation.
+ */
+ return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG;
}
@@ -270,140 +270,140 @@ vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn,
*/
static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- vfp_put_float(state, vfp_single_packed_abs(m), sd);
- return 0;
+ vfp_put_float(state, vfp_single_packed_abs(m), sd);
+ return 0;
}
static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- vfp_put_float(state, m, sd);
- return 0;
+ vfp_put_float(state, m, sd);
+ return 0;
}
static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- vfp_put_float(state, vfp_single_packed_negate(m), sd);
- return 0;
+ vfp_put_float(state, vfp_single_packed_negate(m), sd);
+ return 0;
}
static const u16 sqrt_oddadjust[] = {
- 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
- 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
+ 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0,
+ 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67
};
static const u16 sqrt_evenadjust[] = {
- 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
- 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
+ 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e,
+ 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002
};
u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
{
- int index;
- u32 z, a;
-
- if ((significand & 0xc0000000) != 0x40000000) {
- pr_debug("VFP: estimate_sqrt: invalid significand\n");
- }
-
- a = significand << 1;
- index = (a >> 27) & 15;
- if (exponent & 1) {
- z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
- z = ((a / z) << 14) + (z << 15);
- a >>= 1;
- } else {
- z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
- z = a / z + z;
- z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
- if (z <= a)
- return (s32)a >> 1;
- }
- {
- u64 v = (u64)a << 31;
- do_div(v, z);
- return v + (z >> 1);
- }
+ int index;
+ u32 z, a;
+
+ if ((significand & 0xc0000000) != 0x40000000) {
+ pr_debug("VFP: estimate_sqrt: invalid significand\n");
+ }
+
+ a = significand << 1;
+ index = (a >> 27) & 15;
+ if (exponent & 1) {
+ z = 0x4000 + (a >> 17) - sqrt_oddadjust[index];
+ z = ((a / z) << 14) + (z << 15);
+ a >>= 1;
+ } else {
+ z = 0x8000 + (a >> 17) - sqrt_evenadjust[index];
+ z = a / z + z;
+ z = (z >= 0x20000) ? 0xffff8000 : (z << 15);
+ if (z <= a)
+ return (s32)a >> 1;
+ }
+ {
+ u64 v = (u64)a << 31;
+ do_div(v, z);
+ return (u32)(v + (z >> 1));
+ }
}
static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- struct vfp_single vsm, vsd, *vsp;
- int ret, tm;
-
- vfp_single_unpack(&vsm, m);
- tm = vfp_single_type(&vsm);
- if (tm & (VFP_NAN|VFP_INFINITY)) {
- vsp = &vsd;
-
- if (tm & VFP_NAN)
- ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
- else if (vsm.sign == 0) {
- sqrt_copy:
- vsp = &vsm;
- ret = 0;
- } else {
- sqrt_invalid:
- vsp = &vfp_single_default_qnan;
- ret = FPSCR_IOC;
- }
- vfp_put_float(state, vfp_single_pack(vsp), sd);
- return ret;
- }
-
- /*
- * sqrt(+/- 0) == +/- 0
- */
- if (tm & VFP_ZERO)
- goto sqrt_copy;
-
- /*
- * Normalise a denormalised number
- */
- if (tm & VFP_DENORMAL)
- vfp_single_normalise_denormal(&vsm);
-
- /*
- * sqrt(<0) = invalid
- */
- if (vsm.sign)
- goto sqrt_invalid;
-
- vfp_single_dump("sqrt", &vsm);
-
- /*
- * Estimate the square root.
- */
- vsd.sign = 0;
- vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
- vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
-
- vfp_single_dump("sqrt estimate", &vsd);
-
- /*
- * And now adjust.
- */
- if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
- if (vsd.significand < 2) {
- vsd.significand = 0xffffffff;
- } else {
- u64 term;
- s64 rem;
- vsm.significand <<= !(vsm.exponent & 1);
- term = (u64)vsd.significand * vsd.significand;
- rem = ((u64)vsm.significand << 32) - term;
-
- pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
-
- while (rem < 0) {
- vsd.significand -= 1;
- rem += ((u64)vsd.significand << 1) | 1;
- }
- vsd.significand |= rem != 0;
- }
- }
- vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
-
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt");
+ struct vfp_single vsm, vsd, *vsp;
+ int ret, tm;
+
+ vfp_single_unpack(&vsm, m);
+ tm = vfp_single_type(&vsm);
+ if (tm & (VFP_NAN|VFP_INFINITY)) {
+ vsp = &vsd;
+
+ if (tm & VFP_NAN)
+ ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr);
+ else if (vsm.sign == 0) {
+sqrt_copy:
+ vsp = &vsm;
+ ret = 0;
+ } else {
+sqrt_invalid:
+ vsp = &vfp_single_default_qnan;
+ ret = FPSCR_IOC;
+ }
+ vfp_put_float(state, vfp_single_pack(vsp), sd);
+ return ret;
+ }
+
+ /*
+ * sqrt(+/- 0) == +/- 0
+ */
+ if (tm & VFP_ZERO)
+ goto sqrt_copy;
+
+ /*
+ * Normalise a denormalised number
+ */
+ if (tm & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsm);
+
+ /*
+ * sqrt(<0) = invalid
+ */
+ if (vsm.sign)
+ goto sqrt_invalid;
+
+ vfp_single_dump("sqrt", &vsm);
+
+ /*
+ * Estimate the square root.
+ */
+ vsd.sign = 0;
+ vsd.exponent = ((vsm.exponent - 127) >> 1) + 127;
+ vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2;
+
+ vfp_single_dump("sqrt estimate", &vsd);
+
+ /*
+ * And now adjust.
+ */
+ if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) {
+ if (vsd.significand < 2) {
+ vsd.significand = 0xffffffff;
+ } else {
+ u64 term;
+ s64 rem;
+ vsm.significand <<= !(vsm.exponent & 1);
+ term = (u64)vsd.significand * vsd.significand;
+ rem = ((u64)vsm.significand << 32) - term;
+
+ pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem);
+
+ while (rem < 0) {
+ vsd.significand -= 1;
+ rem += ((u64)vsd.significand << 1) | 1;
+ }
+ vsd.significand |= rem != 0;
+ }
+ }
+ vsd.significand = vfp_shiftright32jamming(vsd.significand, 1);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt");
}
/*
@@ -414,305 +414,346 @@ static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 f
*/
static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr)
{
- s32 d;
- u32 ret = 0;
-
- d = vfp_get_float(state, sd);
- if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
- ret |= FPSCR_C | FPSCR_V;
- if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
- /*
- * Signalling NaN, or signalling on quiet NaN
- */
- ret |= FPSCR_IOC;
- }
-
- if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
- ret |= FPSCR_C | FPSCR_V;
- if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
- /*
- * Signalling NaN, or signalling on quiet NaN
- */
- ret |= FPSCR_IOC;
- }
-
- if (ret == 0) {
- if (d == m || vfp_single_packed_abs(d | m) == 0) {
- /*
- * equal
- */
- ret |= FPSCR_Z | FPSCR_C;
- } else if (vfp_single_packed_sign(d ^ m)) {
- /*
- * different signs
- */
- if (vfp_single_packed_sign(d))
- /*
- * d is negative, so d < m
- */
- ret |= FPSCR_N;
- else
- /*
- * d is positive, so d > m
- */
- ret |= FPSCR_C;
- } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
- /*
- * d < m
- */
- ret |= FPSCR_N;
- } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
- /*
- * d > m
- */
- ret |= FPSCR_C;
- }
- }
- return ret;
+ s32 d;
+ u32 ret = 0;
+
+ d = vfp_get_float(state, sd);
+ if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) {
+ ret |= FPSCR_C | FPSCR_V;
+ if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
+ /*
+ * Signalling NaN, or signalling on quiet NaN
+ */
+ ret |= FPSCR_IOC;
+ }
+
+ if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) {
+ ret |= FPSCR_C | FPSCR_V;
+ if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1))))
+ /*
+ * Signalling NaN, or signalling on quiet NaN
+ */
+ ret |= FPSCR_IOC;
+ }
+
+ if (ret == 0) {
+ if (d == m || vfp_single_packed_abs(d | m) == 0) {
+ /*
+ * equal
+ */
+ ret |= FPSCR_Z | FPSCR_C;
+ } else if (vfp_single_packed_sign(d ^ m)) {
+ /*
+ * different signs
+ */
+ if (vfp_single_packed_sign(d))
+ /*
+ * d is negative, so d < m
+ */
+ ret |= FPSCR_N;
+ else
+ /*
+ * d is positive, so d > m
+ */
+ ret |= FPSCR_C;
+ } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) {
+ /*
+ * d < m
+ */
+ ret |= FPSCR_N;
+ } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) {
+ /*
+ * d > m
+ */
+ ret |= FPSCR_C;
+ }
+ }
+ return ret;
}
static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- return vfp_compare(state, sd, 0, m, fpscr);
+ return vfp_compare(state, sd, 0, m, fpscr);
}
static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- return vfp_compare(state, sd, 1, m, fpscr);
+ return vfp_compare(state, sd, 1, m, fpscr);
}
static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- return vfp_compare(state, sd, 0, 0, fpscr);
+ return vfp_compare(state, sd, 0, 0, fpscr);
}
static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- return vfp_compare(state, sd, 1, 0, fpscr);
+ return vfp_compare(state, sd, 1, 0, fpscr);
+}
+
+static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ichfly for internal use only
+{
+ struct vfp_single vsm;
+ struct vfp_double vdd;
+ int tm;
+ u32 exceptions = 0;
+
+ vfp_single_unpack(&vsm, m);
+
+ tm = vfp_single_type(&vsm);
+
+ /*
+ * If we have a signalling NaN, signal invalid operation.
+ */
+ if (tm == VFP_SNAN)
+ exceptions = FPSCR_IOC;
+
+ if (tm & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsm);
+
+ vdd.sign = vsm.sign;
+ vdd.significand = (u64)vsm.significand << 32;
+
+ /*
+ * If we have an infinity or NaN, the exponent must be 2047.
+ */
+ if (tm & (VFP_INFINITY | VFP_NAN)) {
+ vdd.exponent = 2047;
+ if (tm == VFP_QNAN)
+ vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
+ goto pack_nan;
+ }
+ else if (tm & VFP_ZERO)
+ vdd.exponent = 0;
+ else
+ vdd.exponent = vsm.exponent + (1023 - 127);
+pack_nan:
+ vfp_double_normaliseroundintern(state, &vdd, fpscr, exceptions, "fcvtd");
+ return vfp_double_pack(&vdd);
}
static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr)
{
- struct vfp_single vsm;
- struct vfp_double vdd;
- int tm;
- u32 exceptions = 0;
-
- vfp_single_unpack(&vsm, m);
-
- tm = vfp_single_type(&vsm);
-
- /*
- * If we have a signalling NaN, signal invalid operation.
- */
- if (tm == VFP_SNAN)
- exceptions = FPSCR_IOC;
-
- if (tm & VFP_DENORMAL)
- vfp_single_normalise_denormal(&vsm);
-
- vdd.sign = vsm.sign;
- vdd.significand = (u64)vsm.significand << 32;
-
- /*
- * If we have an infinity or NaN, the exponent must be 2047.
- */
- if (tm & (VFP_INFINITY|VFP_NAN)) {
- vdd.exponent = 2047;
- if (tm == VFP_QNAN)
- vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
- goto pack_nan;
- } else if (tm & VFP_ZERO)
- vdd.exponent = 0;
- else
- vdd.exponent = vsm.exponent + (1023 - 127);
-
- return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
-
- pack_nan:
- vfp_put_double(state, vfp_double_pack(&vdd), dd);
- return exceptions;
+ struct vfp_single vsm;
+ struct vfp_double vdd;
+ int tm;
+ u32 exceptions = 0;
+
+ vfp_single_unpack(&vsm, m);
+
+ tm = vfp_single_type(&vsm);
+
+ /*
+ * If we have a signalling NaN, signal invalid operation.
+ */
+ if (tm == VFP_SNAN)
+ exceptions = FPSCR_IOC;
+
+ if (tm & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsm);
+
+ vdd.sign = vsm.sign;
+ vdd.significand = (u64)vsm.significand << 32;
+
+ /*
+ * If we have an infinity or NaN, the exponent must be 2047.
+ */
+ if (tm & (VFP_INFINITY|VFP_NAN)) {
+ vdd.exponent = 2047;
+ if (tm == VFP_QNAN)
+ vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
+ goto pack_nan;
+ } else if (tm & VFP_ZERO)
+ vdd.exponent = 0;
+ else
+ vdd.exponent = vsm.exponent + (1023 - 127);
+
+ return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd");
+
+pack_nan:
+ vfp_put_double(state, vfp_double_pack(&vdd), dd);
+ return exceptions;
}
static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- struct vfp_single vs;
+ struct vfp_single vs;
- vs.sign = 0;
- vs.exponent = 127 + 31 - 1;
- vs.significand = (u32)m;
+ vs.sign = 0;
+ vs.exponent = 127 + 31 - 1;
+ vs.significand = (u32)m;
- return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito");
+ return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito");
}
static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- struct vfp_single vs;
+ struct vfp_single vs;
- vs.sign = (m & 0x80000000) >> 16;
- vs.exponent = 127 + 31 - 1;
- vs.significand = vs.sign ? -m : m;
+ vs.sign = (m & 0x80000000) >> 16;
+ vs.exponent = 127 + 31 - 1;
+ vs.significand = vs.sign ? -m : m;
- return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito");
+ return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito");
}
static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- struct vfp_single vsm;
- u32 d, exceptions = 0;
- int rmode = fpscr & FPSCR_RMODE_MASK;
- int tm;
-
- vfp_single_unpack(&vsm, m);
- vfp_single_dump("VSM", &vsm);
-
- /*
- * Do we have a denormalised number?
- */
- tm = vfp_single_type(&vsm);
- if (tm & VFP_DENORMAL)
- exceptions |= FPSCR_IDC;
-
- if (tm & VFP_NAN)
- vsm.sign = 0;
-
- if (vsm.exponent >= 127 + 32) {
- d = vsm.sign ? 0 : 0xffffffff;
- exceptions = FPSCR_IOC;
- } else if (vsm.exponent >= 127 - 1) {
- int shift = 127 + 31 - vsm.exponent;
- u32 rem, incr = 0;
-
- /*
- * 2^0 <= m < 2^32-2^8
- */
- d = (vsm.significand << 1) >> shift;
- rem = vsm.significand << (33 - shift);
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 0x80000000;
- if ((d & 1) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
- incr = ~0;
- }
-
- if ((rem + incr) < rem) {
- if (d < 0xffffffff)
- d += 1;
- else
- exceptions |= FPSCR_IOC;
- }
-
- if (d && vsm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
- } else if (rem)
- exceptions |= FPSCR_IXC;
- } else {
- d = 0;
- if (vsm.exponent | vsm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
- d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
- d = 0;
- exceptions |= FPSCR_IOC;
- }
- }
- }
-
- pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
-
- vfp_put_float(state, d, sd);
-
- return exceptions;
+ struct vfp_single vsm;
+ u32 d, exceptions = 0;
+ int rmode = fpscr & FPSCR_RMODE_MASK;
+ int tm;
+
+ vfp_single_unpack(&vsm, m);
+ vfp_single_dump("VSM", &vsm);
+
+ /*
+ * Do we have a denormalised number?
+ */
+ tm = vfp_single_type(&vsm);
+ if (tm & VFP_DENORMAL)
+ exceptions |= FPSCR_IDC;
+
+ if (tm & VFP_NAN)
+ vsm.sign = 0;
+
+ if (vsm.exponent >= 127 + 32) {
+ d = vsm.sign ? 0 : 0xffffffff;
+ exceptions = FPSCR_IOC;
+ } else if (vsm.exponent >= 127 - 1) {
+ int shift = 127 + 31 - vsm.exponent;
+ u32 rem, incr = 0;
+
+ /*
+ * 2^0 <= m < 2^32-2^8
+ */
+ d = (vsm.significand << 1) >> shift;
+ rem = vsm.significand << (33 - shift);
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 0x80000000;
+ if ((d & 1) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
+ incr = ~0;
+ }
+
+ if ((rem + incr) < rem) {
+ if (d < 0xffffffff)
+ d += 1;
+ else
+ exceptions |= FPSCR_IOC;
+ }
+
+ if (d && vsm.sign) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ } else if (rem)
+ exceptions |= FPSCR_IXC;
+ } else {
+ d = 0;
+ if (vsm.exponent | vsm.significand) {
+ exceptions |= FPSCR_IXC;
+ if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
+ d = 1;
+ else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ }
+ }
+ }
+
+ pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+
+ vfp_put_float(state, d, sd);
+
+ return exceptions;
}
static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO);
+ return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO);
}
static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- struct vfp_single vsm;
- u32 d, exceptions = 0;
- int rmode = fpscr & FPSCR_RMODE_MASK;
- int tm;
-
- vfp_single_unpack(&vsm, m);
- vfp_single_dump("VSM", &vsm);
-
- /*
- * Do we have a denormalised number?
- */
- tm = vfp_single_type(&vsm);
- if (vfp_single_type(&vsm) & VFP_DENORMAL)
- exceptions |= FPSCR_IDC;
-
- if (tm & VFP_NAN) {
- d = 0;
- exceptions |= FPSCR_IOC;
- } else if (vsm.exponent >= 127 + 32) {
- /*
- * m >= 2^31-2^7: invalid
- */
- d = 0x7fffffff;
- if (vsm.sign)
- d = ~d;
- exceptions |= FPSCR_IOC;
- } else if (vsm.exponent >= 127 - 1) {
- int shift = 127 + 31 - vsm.exponent;
- u32 rem, incr = 0;
-
- /* 2^0 <= m <= 2^31-2^7 */
- d = (vsm.significand << 1) >> shift;
- rem = vsm.significand << (33 - shift);
-
- if (rmode == FPSCR_ROUND_NEAREST) {
- incr = 0x80000000;
- if ((d & 1) == 0)
- incr -= 1;
- } else if (rmode == FPSCR_ROUND_TOZERO) {
- incr = 0;
- } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
- incr = ~0;
- }
-
- if ((rem + incr) < rem && d < 0xffffffff)
- d += 1;
- if (d > 0x7fffffff + (vsm.sign != 0)) {
- d = 0x7fffffff + (vsm.sign != 0);
- exceptions |= FPSCR_IOC;
- } else if (rem)
- exceptions |= FPSCR_IXC;
-
- if (vsm.sign)
- d = -d;
- } else {
- d = 0;
- if (vsm.exponent | vsm.significand) {
- exceptions |= FPSCR_IXC;
- if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
- d = 1;
- else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign)
- d = -1;
- }
- }
-
- pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
-
- vfp_put_float(state, (s32)d, sd);
-
- return exceptions;
+ struct vfp_single vsm;
+ u32 d, exceptions = 0;
+ int rmode = fpscr & FPSCR_RMODE_MASK;
+ int tm;
+
+ vfp_single_unpack(&vsm, m);
+ vfp_single_dump("VSM", &vsm);
+
+ /*
+ * Do we have a denormalised number?
+ */
+ tm = vfp_single_type(&vsm);
+ if (vfp_single_type(&vsm) & VFP_DENORMAL)
+ exceptions |= FPSCR_IDC;
+
+ if (tm & VFP_NAN) {
+ d = 0;
+ exceptions |= FPSCR_IOC;
+ } else if (vsm.exponent >= 127 + 32) {
+ /*
+ * m >= 2^31-2^7: invalid
+ */
+ d = 0x7fffffff;
+ if (vsm.sign)
+ d = ~d;
+ exceptions |= FPSCR_IOC;
+ } else if (vsm.exponent >= 127 - 1) {
+ int shift = 127 + 31 - vsm.exponent;
+ u32 rem, incr = 0;
+
+ /* 2^0 <= m <= 2^31-2^7 */
+ d = (vsm.significand << 1) >> shift;
+ rem = vsm.significand << (33 - shift);
+
+ if (rmode == FPSCR_ROUND_NEAREST) {
+ incr = 0x80000000;
+ if ((d & 1) == 0)
+ incr -= 1;
+ } else if (rmode == FPSCR_ROUND_TOZERO) {
+ incr = 0;
+ } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) {
+ incr = ~0;
+ }
+
+ if ((rem + incr) < rem && d < 0xffffffff)
+ d += 1;
+ if (d > (0x7fffffffu + (vsm.sign != 0))) {
+ d = (0x7fffffffu + (vsm.sign != 0));
+ exceptions |= FPSCR_IOC;
+ } else if (rem)
+ exceptions |= FPSCR_IXC;
+
+ if (vsm.sign)
+ d = 0-d;
+ } else {
+ d = 0;
+ if (vsm.exponent | vsm.significand) {
+ exceptions |= FPSCR_IXC;
+ if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0)
+ d = 1;
+ else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign)
+ d = -1;
+ }
+ }
+
+ pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions);
+
+ vfp_put_float(state, (s32)d, sd);
+
+ return exceptions;
}
static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr)
{
- return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO);
+ return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO);
}
static struct op fops_ext[] = {
@@ -752,200 +793,237 @@ static struct op fops_ext[] = {
static u32
vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn,
- struct vfp_single *vsm, u32 fpscr)
+ struct vfp_single *vsm, u32 fpscr)
{
- struct vfp_single *vsp;
- u32 exceptions = 0;
- int tn, tm;
-
- tn = vfp_single_type(vsn);
- tm = vfp_single_type(vsm);
-
- if (tn & tm & VFP_INFINITY) {
- /*
- * Two infinities. Are they different signs?
- */
- if (vsn->sign ^ vsm->sign) {
- /*
- * different signs -> invalid
- */
- exceptions = FPSCR_IOC;
- vsp = &vfp_single_default_qnan;
- } else {
- /*
- * same signs -> valid
- */
- vsp = vsn;
- }
- } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
- /*
- * One infinity and one number -> infinity
- */
- vsp = vsn;
- } else {
- /*
- * 'n' is a NaN of some type
- */
- return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
- }
- *vsd = *vsp;
- return exceptions;
+ struct vfp_single *vsp;
+ u32 exceptions = 0;
+ int tn, tm;
+
+ tn = vfp_single_type(vsn);
+ tm = vfp_single_type(vsm);
+
+ if (tn & tm & VFP_INFINITY) {
+ /*
+ * Two infinities. Are they different signs?
+ */
+ if (vsn->sign ^ vsm->sign) {
+ /*
+ * different signs -> invalid
+ */
+ exceptions = FPSCR_IOC;
+ vsp = &vfp_single_default_qnan;
+ } else {
+ /*
+ * same signs -> valid
+ */
+ vsp = vsn;
+ }
+ } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) {
+ /*
+ * One infinity and one number -> infinity
+ */
+ vsp = vsn;
+ } else {
+ /*
+ * 'n' is a NaN of some type
+ */
+ return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
+ }
+ *vsd = *vsp;
+ return exceptions;
}
static u32
vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn,
- struct vfp_single *vsm, u32 fpscr)
+ struct vfp_single *vsm, u32 fpscr)
{
- u32 exp_diff, m_sig;
-
- if (vsn->significand & 0x80000000 ||
- vsm->significand & 0x80000000) {
- pr_info("VFP: bad FP values\n");
- vfp_single_dump("VSN", vsn);
- vfp_single_dump("VSM", vsm);
- }
-
- /*
- * Ensure that 'n' is the largest magnitude number. Note that
- * if 'n' and 'm' have equal exponents, we do not swap them.
- * This ensures that NaN propagation works correctly.
- */
- if (vsn->exponent < vsm->exponent) {
- struct vfp_single *t = vsn;
- vsn = vsm;
- vsm = t;
- }
-
- /*
- * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
- * infinity or a NaN here.
- */
- if (vsn->exponent == 255)
- return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
-
- /*
- * We have two proper numbers, where 'vsn' is the larger magnitude.
- *
- * Copy 'n' to 'd' before doing the arithmetic.
- */
- *vsd = *vsn;
-
- /*
- * Align both numbers.
- */
- exp_diff = vsn->exponent - vsm->exponent;
- m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
-
- /*
- * If the signs are different, we are really subtracting.
- */
- if (vsn->sign ^ vsm->sign) {
- m_sig = vsn->significand - m_sig;
- if ((s32)m_sig < 0) {
- vsd->sign = vfp_sign_negate(vsd->sign);
- m_sig = -m_sig;
- } else if (m_sig == 0) {
- vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
- FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
- }
- } else {
- m_sig = vsn->significand + m_sig;
- }
- vsd->significand = m_sig;
-
- return 0;
+ u32 exp_diff, m_sig;
+
+ if (vsn->significand & 0x80000000 ||
+ vsm->significand & 0x80000000) {
+ pr_info("VFP: bad FP values in %s\n", __func__);
+ vfp_single_dump("VSN", vsn);
+ vfp_single_dump("VSM", vsm);
+ }
+
+ /*
+ * Ensure that 'n' is the largest magnitude number. Note that
+ * if 'n' and 'm' have equal exponents, we do not swap them.
+ * This ensures that NaN propagation works correctly.
+ */
+ if (vsn->exponent < vsm->exponent) {
+ struct vfp_single *t = vsn;
+ vsn = vsm;
+ vsm = t;
+ }
+
+ /*
+ * Is 'n' an infinity or a NaN? Note that 'm' may be a number,
+ * infinity or a NaN here.
+ */
+ if (vsn->exponent == 255)
+ return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr);
+
+ /*
+ * We have two proper numbers, where 'vsn' is the larger magnitude.
+ *
+ * Copy 'n' to 'd' before doing the arithmetic.
+ */
+ *vsd = *vsn;
+
+ /*
+ * Align both numbers.
+ */
+ exp_diff = vsn->exponent - vsm->exponent;
+ m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff);
+
+ /*
+ * If the signs are different, we are really subtracting.
+ */
+ if (vsn->sign ^ vsm->sign) {
+ m_sig = vsn->significand - m_sig;
+ if ((s32)m_sig < 0) {
+ vsd->sign = vfp_sign_negate(vsd->sign);
+ m_sig = 0-m_sig;
+ } else if (m_sig == 0) {
+ vsd->sign = (fpscr & FPSCR_RMODE_MASK) ==
+ FPSCR_ROUND_MINUSINF ? 0x8000 : 0;
+ }
+ } else {
+ m_sig = vsn->significand + m_sig;
+ }
+ vsd->significand = m_sig;
+
+ return 0;
}
static u32
vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr)
{
- vfp_single_dump("VSN", vsn);
- vfp_single_dump("VSM", vsm);
-
- /*
- * Ensure that 'n' is the largest magnitude number. Note that
- * if 'n' and 'm' have equal exponents, we do not swap them.
- * This ensures that NaN propagation works correctly.
- */
- if (vsn->exponent < vsm->exponent) {
- struct vfp_single *t = vsn;
- vsn = vsm;
- vsm = t;
- pr_debug("VFP: swapping M <-> N\n");
- }
-
- vsd->sign = vsn->sign ^ vsm->sign;
-
- /*
- * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
- */
- if (vsn->exponent == 255) {
- if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
- return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
- if ((vsm->exponent | vsm->significand) == 0) {
- *vsd = vfp_single_default_qnan;
- return FPSCR_IOC;
- }
- vsd->exponent = vsn->exponent;
- vsd->significand = 0;
- return 0;
- }
-
- /*
- * If 'm' is zero, the result is always zero. In this case,
- * 'n' may be zero or a number, but it doesn't matter which.
- */
- if ((vsm->exponent | vsm->significand) == 0) {
- vsd->exponent = 0;
- vsd->significand = 0;
- return 0;
- }
-
- /*
- * We add 2 to the destination exponent for the same reason as
- * the addition case - though this time we have +1 from each
- * input operand.
- */
- vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
- vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
-
- vfp_single_dump("VSD", vsd);
- return 0;
+ vfp_single_dump("VSN", vsn);
+ vfp_single_dump("VSM", vsm);
+
+ /*
+ * Ensure that 'n' is the largest magnitude number. Note that
+ * if 'n' and 'm' have equal exponents, we do not swap them.
+ * This ensures that NaN propagation works correctly.
+ */
+ if (vsn->exponent < vsm->exponent) {
+ struct vfp_single *t = vsn;
+ vsn = vsm;
+ vsm = t;
+ pr_debug("VFP: swapping M <-> N\n");
+ }
+
+ vsd->sign = vsn->sign ^ vsm->sign;
+
+ /*
+ * If 'n' is an infinity or NaN, handle it. 'm' may be anything.
+ */
+ if (vsn->exponent == 255) {
+ if (vsn->significand || (vsm->exponent == 255 && vsm->significand))
+ return vfp_propagate_nan(vsd, vsn, vsm, fpscr);
+ if ((vsm->exponent | vsm->significand) == 0) {
+ *vsd = vfp_single_default_qnan;
+ return FPSCR_IOC;
+ }
+ vsd->exponent = vsn->exponent;
+ vsd->significand = 0;
+ return 0;
+ }
+
+ /*
+ * If 'm' is zero, the result is always zero. In this case,
+ * 'n' may be zero or a number, but it doesn't matter which.
+ */
+ if ((vsm->exponent | vsm->significand) == 0) {
+ vsd->exponent = 0;
+ vsd->significand = 0;
+ return 0;
+ }
+
+ /*
+ * We add 2 to the destination exponent for the same reason as
+ * the addition case - though this time we have +1 from each
+ * input operand.
+ */
+ vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2;
+ vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand);
+
+ vfp_single_dump("VSD", vsd);
+ return 0;
}
#define NEG_MULTIPLY (1 << 0)
#define NEG_SUBTRACT (1 << 1)
static u32
-vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func)
+vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func)
{
- struct vfp_single vsd, vsp, vsn, vsm;
- u32 exceptions;
- s32 v;
+
+ {
+ struct vfp_single vsd, vsp, vsn, vsm;
+ u32 exceptions;
+ s32 v;
+
+
+
+ v = vfp_get_float(state, sn);
+ pr_debug("VFP: s%u = %08x\n", sn, v);
+ vfp_single_unpack(&vsn, v);
+ if (vsn.exponent == 0 && vsn.significand)
+ vfp_single_normalise_denormal(&vsn);
+
+ vfp_single_unpack(&vsm, m);
+ if (vsm.exponent == 0 && vsm.significand)
+ vfp_single_normalise_denormal(&vsm);
+
+ exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
+
+ if (negate & NEG_MULTIPLY)
+ vsp.sign = vfp_sign_negate(vsp.sign);
+
+ v = vfp_get_float(state, sd);
+ pr_debug("VFP: s%u = %08x\n", sd, v);
+ vfp_single_unpack(&vsn, v);
+ if (negate & NEG_SUBTRACT)
+ vsn.sign = vfp_sign_negate(vsn.sign);
+
+ exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
+ }
+
+ struct vfp_double vsd, vsp, vsn, vsm;
+ u32 exceptions;
+ s32 v;
+ s64 vd;
+ s64 md;
+
+ v = vfp_get_float(state, sn);
+ vd = vfp_single_to_doubleintern(state, v, fpscr);
+ vfp_double_unpack(&vsn, vd);
+
+ md = vfp_single_to_doubleintern(state, m, fpscr);
+ vfp_double_unpack(&vsm, md);
+
+ exceptions = vfp_double_multiply(&vsp, &vsn, &vsm, fpscr);
+ if (negate & NEG_MULTIPLY)
+ vsp.sign = vfp_sign_negate(vsp.sign);
- v = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, v);
- vfp_single_unpack(&vsn, v);
- if (vsn.exponent == 0 && vsn.significand)
- vfp_single_normalise_denormal(&vsn);
+ v = vfp_get_float(state, sd);
+ vd = vfp_single_to_doubleintern(state, v, fpscr);
+ vfp_double_unpack(&vsn, vd);
- vfp_single_unpack(&vsm, m);
- if (vsm.exponent == 0 && vsm.significand)
- vfp_single_normalise_denormal(&vsm);
+ if (negate & NEG_SUBTRACT)
+ vsn.sign = vfp_sign_negate(vsn.sign);
- exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr);
- if (negate & NEG_MULTIPLY)
- vsp.sign = vfp_sign_negate(vsp.sign);
+ exceptions |= vfp_double_add(&vsd, &vsn, &vsp, fpscr);
- v = vfp_get_float(state, sd);
- pr_debug("VFP: s%u = %08x\n", sd, v);
- vfp_single_unpack(&vsn, v);
- if (negate & NEG_SUBTRACT)
- vsn.sign = vfp_sign_negate(vsn.sign);
+ s64 debug = vfp_double_pack(&vsd);
- exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr);
+ return vfp_double_fcvtsinterncutting(state, sd, &vsd, fpscr);
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func);
}
/*
@@ -957,8 +1035,8 @@ vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fp
*/
static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
- return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac");
}
/*
@@ -966,8 +1044,8 @@ static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn);
- return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn);
+ return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac");
}
/*
@@ -975,8 +1053,8 @@ static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
*/
static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
- return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc");
}
/*
@@ -984,8 +1062,8 @@ static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
- return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc");
}
/*
@@ -993,22 +1071,22 @@ static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
*/
static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- struct vfp_single vsd, vsn, vsm;
- u32 exceptions;
- s32 n = vfp_get_float(state, sn);
+ struct vfp_single vsd, vsn, vsm;
+ u32 exceptions;
+ s32 n = vfp_get_float(state, sn);
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n);
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n);
- vfp_single_unpack(&vsn, n);
- if (vsn.exponent == 0 && vsn.significand)
- vfp_single_normalise_denormal(&vsn);
+ vfp_single_unpack(&vsn, n);
+ if (vsn.exponent == 0 && vsn.significand)
+ vfp_single_normalise_denormal(&vsn);
- vfp_single_unpack(&vsm, m);
- if (vsm.exponent == 0 && vsm.significand)
- vfp_single_normalise_denormal(&vsm);
+ vfp_single_unpack(&vsm, m);
+ if (vsm.exponent == 0 && vsm.significand)
+ vfp_single_normalise_denormal(&vsm);
- exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul");
+ exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul");
}
/*
@@ -1016,23 +1094,23 @@ static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- struct vfp_single vsd, vsn, vsm;
- u32 exceptions;
- s32 n = vfp_get_float(state, sn);
+ struct vfp_single vsd, vsn, vsm;
+ u32 exceptions;
+ s32 n = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, n);
+ pr_debug("VFP: s%u = %08x\n", sn, n);
- vfp_single_unpack(&vsn, n);
- if (vsn.exponent == 0 && vsn.significand)
- vfp_single_normalise_denormal(&vsn);
+ vfp_single_unpack(&vsn, n);
+ if (vsn.exponent == 0 && vsn.significand)
+ vfp_single_normalise_denormal(&vsn);
- vfp_single_unpack(&vsm, m);
- if (vsm.exponent == 0 && vsm.significand)
- vfp_single_normalise_denormal(&vsm);
+ vfp_single_unpack(&vsm, m);
+ if (vsm.exponent == 0 && vsm.significand)
+ vfp_single_normalise_denormal(&vsm);
- exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
- vsd.sign = vfp_sign_negate(vsd.sign);
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul");
+ exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr);
+ vsd.sign = vfp_sign_negate(vsd.sign);
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul");
}
/*
@@ -1040,26 +1118,26 @@ static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr
*/
static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- struct vfp_single vsd, vsn, vsm;
- u32 exceptions;
- s32 n = vfp_get_float(state, sn);
+ struct vfp_single vsd, vsn, vsm;
+ u32 exceptions;
+ s32 n = vfp_get_float(state, sn);
- pr_debug("VFP: s%u = %08x\n", sn, n);
+ pr_debug("VFP: s%u = %08x\n", sn, n);
- /*
- * Unpack and normalise denormals.
- */
- vfp_single_unpack(&vsn, n);
- if (vsn.exponent == 0 && vsn.significand)
- vfp_single_normalise_denormal(&vsn);
+ /*
+ * Unpack and normalise denormals.
+ */
+ vfp_single_unpack(&vsn, n);
+ if (vsn.exponent == 0 && vsn.significand)
+ vfp_single_normalise_denormal(&vsn);
- vfp_single_unpack(&vsm, m);
- if (vsm.exponent == 0 && vsm.significand)
- vfp_single_normalise_denormal(&vsm);
+ vfp_single_unpack(&vsm, m);
+ if (vsm.exponent == 0 && vsm.significand)
+ vfp_single_normalise_denormal(&vsm);
- exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr);
+ exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr);
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd");
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd");
}
/*
@@ -1067,11 +1145,11 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
- /*
- * Subtraction is addition with one sign inverted.
- */
- return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr);
+ pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd);
+ /*
+ * Subtraction is addition with one sign inverted.
+ */
+ return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr);
}
/*
@@ -1079,107 +1157,107 @@ static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
*/
static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
{
- struct vfp_single vsd, vsn, vsm;
- u32 exceptions = 0;
- s32 n = vfp_get_float(state, sn);
- int tm, tn;
-
- pr_debug("VFP: s%u = %08x\n", sn, n);
-
- vfp_single_unpack(&vsn, n);
- vfp_single_unpack(&vsm, m);
-
- vsd.sign = vsn.sign ^ vsm.sign;
-
- tn = vfp_single_type(&vsn);
- tm = vfp_single_type(&vsm);
-
- /*
- * Is n a NAN?
- */
- if (tn & VFP_NAN)
- goto vsn_nan;
-
- /*
- * Is m a NAN?
- */
- if (tm & VFP_NAN)
- goto vsm_nan;
-
- /*
- * If n and m are infinity, the result is invalid
- * If n and m are zero, the result is invalid
- */
- if (tm & tn & (VFP_INFINITY|VFP_ZERO))
- goto invalid;
-
- /*
- * If n is infinity, the result is infinity
- */
- if (tn & VFP_INFINITY)
- goto infinity;
-
- /*
- * If m is zero, raise div0 exception
- */
- if (tm & VFP_ZERO)
- goto divzero;
-
- /*
- * If m is infinity, or n is zero, the result is zero
- */
- if (tm & VFP_INFINITY || tn & VFP_ZERO)
- goto zero;
-
- if (tn & VFP_DENORMAL)
- vfp_single_normalise_denormal(&vsn);
- if (tm & VFP_DENORMAL)
- vfp_single_normalise_denormal(&vsm);
-
- /*
- * Ok, we have two numbers, we can perform division.
- */
- vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
- vsm.significand <<= 1;
- if (vsm.significand <= (2 * vsn.significand)) {
- vsn.significand >>= 1;
- vsd.exponent++;
- }
- {
- u64 significand = (u64)vsn.significand << 32;
- do_div(significand, vsm.significand);
- vsd.significand = significand;
- }
- if ((vsd.significand & 0x3f) == 0)
- vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
-
- return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
-
- vsn_nan:
- exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
- pack:
- vfp_put_float(state, vfp_single_pack(&vsd), sd);
- return exceptions;
-
- vsm_nan:
- exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
- goto pack;
-
- zero:
- vsd.exponent = 0;
- vsd.significand = 0;
- goto pack;
-
- divzero:
- exceptions = FPSCR_DZC;
- infinity:
- vsd.exponent = 255;
- vsd.significand = 0;
- goto pack;
-
- invalid:
- vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
- return FPSCR_IOC;
+ struct vfp_single vsd, vsn, vsm;
+ u32 exceptions = 0;
+ s32 n = vfp_get_float(state, sn);
+ int tm, tn;
+
+ pr_debug("VFP: s%u = %08x\n", sn, n);
+
+ vfp_single_unpack(&vsn, n);
+ vfp_single_unpack(&vsm, m);
+
+ vsd.sign = vsn.sign ^ vsm.sign;
+
+ tn = vfp_single_type(&vsn);
+ tm = vfp_single_type(&vsm);
+
+ /*
+ * Is n a NAN?
+ */
+ if (tn & VFP_NAN)
+ goto vsn_nan;
+
+ /*
+ * Is m a NAN?
+ */
+ if (tm & VFP_NAN)
+ goto vsm_nan;
+
+ /*
+ * If n and m are infinity, the result is invalid
+ * If n and m are zero, the result is invalid
+ */
+ if (tm & tn & (VFP_INFINITY|VFP_ZERO))
+ goto invalid;
+
+ /*
+ * If n is infinity, the result is infinity
+ */
+ if (tn & VFP_INFINITY)
+ goto infinity;
+
+ /*
+ * If m is zero, raise div0 exception
+ */
+ if (tm & VFP_ZERO)
+ goto divzero;
+
+ /*
+ * If m is infinity, or n is zero, the result is zero
+ */
+ if (tm & VFP_INFINITY || tn & VFP_ZERO)
+ goto zero;
+
+ if (tn & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsn);
+ if (tm & VFP_DENORMAL)
+ vfp_single_normalise_denormal(&vsm);
+
+ /*
+ * Ok, we have two numbers, we can perform division.
+ */
+ vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1;
+ vsm.significand <<= 1;
+ if (vsm.significand <= (2 * vsn.significand)) {
+ vsn.significand >>= 1;
+ vsd.exponent++;
+ }
+ {
+ u64 significand = (u64)vsn.significand << 32;
+ do_div(significand, vsm.significand);
+ vsd.significand = (u32)significand;
+ }
+ if ((vsd.significand & 0x3f) == 0)
+ vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
+
+ return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv");
+
+vsn_nan:
+ exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr);
+pack:
+ vfp_put_float(state, vfp_single_pack(&vsd), sd);
+ return exceptions;
+
+vsm_nan:
+ exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr);
+ goto pack;
+
+zero:
+ vsd.exponent = 0;
+ vsd.significand = 0;
+ goto pack;
+
+divzero:
+ exceptions = FPSCR_DZC;
+infinity:
+ vsd.exponent = 255;
+ vsd.significand = 0;
+ goto pack;
+
+invalid:
+ vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd);
+ return FPSCR_IOC;
}
static struct op fops[] = {
@@ -1199,80 +1277,80 @@ static struct op fops[] = {
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
{
- u32 op = inst & FOP_MASK;
- u32 exceptions = 0;
- unsigned int dest;
- unsigned int sn = vfp_get_sn(inst);
- unsigned int sm = vfp_get_sm(inst);
- unsigned int vecitr, veclen, vecstride;
- struct op *fop;
- pr_debug("In %s\n", __FUNCTION__);
-
- vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
-
- fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
-
- /*
- * fcvtsd takes a dN register number as destination, not sN.
- * Technically, if bit 0 of dd is set, this is an invalid
- * instruction. However, we ignore this for efficiency.
- * It also only operates on scalars.
- */
- if (fop->flags & OP_DD)
- dest = vfp_get_dd(inst);
- else
- dest = vfp_get_sd(inst);
-
- /*
- * If destination bank is zero, vector length is always '1'.
- * ARM DDI0100F C5.1.3, C5.3.2.
- */
- if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
- veclen = 0;
- else
- veclen = fpscr & FPSCR_LENGTH_MASK;
-
- pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
- (veclen >> FPSCR_LENGTH_BIT) + 1);
-
- if (!fop->fn) {
- printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]);
- exit(-1);
- goto invalid;
- }
-
- for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
- s32 m = vfp_get_float(state, sm);
- u32 except;
- char type;
-
- type = fop->flags & OP_DD ? 'd' : 's';
- if (op == FOP_EXT)
- pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
- sm, m);
- else
- pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
- FOP_TO_IDX(op), sm, m);
-
- except = fop->fn(state, dest, sn, m, fpscr);
- pr_debug("VFP: itr%d: exceptions=%08x\n",
- vecitr >> FPSCR_LENGTH_BIT, except);
-
- exceptions |= except;
-
- /*
- * CHECK: It appears to be undefined whether we stop when
- * we encounter an exception. We continue.
- */
- dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
- sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
- if (FREG_BANK(sm) != 0)
- sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
- }
- return exceptions;
-
- invalid:
- return (u32)-1;
+ u32 op = inst & FOP_MASK;
+ u32 exceptions = 0;
+ unsigned int dest;
+ unsigned int sn = vfp_get_sn(inst);
+ unsigned int sm = vfp_get_sm(inst);
+ unsigned int vecitr, veclen, vecstride;
+ struct op *fop;
+ pr_debug("In %s\n", __FUNCTION__);
+
+ vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
+
+ fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
+
+ /*
+ * fcvtsd takes a dN register number as destination, not sN.
+ * Technically, if bit 0 of dd is set, this is an invalid
+ * instruction. However, we ignore this for efficiency.
+ * It also only operates on scalars.
+ */
+ if (fop->flags & OP_DD)
+ dest = vfp_get_dd(inst);
+ else
+ dest = vfp_get_sd(inst);
+
+ /*
+ * If destination bank is zero, vector length is always '1'.
+ * ARM DDI0100F C5.1.3, C5.3.2.
+ */
+ if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
+ veclen = 0;
+ else
+ veclen = fpscr & FPSCR_LENGTH_MASK;
+
+ pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
+ (veclen >> FPSCR_LENGTH_BIT) + 1);
+
+ if (!fop->fn) {
+ printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]);
+ exit(-1);
+ goto invalid;
+ }
+
+ for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
+ s32 m = vfp_get_float(state, sm);
+ u32 except;
+ char type;
+
+ type = fop->flags & OP_DD ? 'd' : 's';
+ if (op == FOP_EXT)
+ pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ sm, m);
+ else
+ pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ FOP_TO_IDX(op), sm, m);
+
+ except = fop->fn(state, dest, sn, m, fpscr);
+ pr_debug("VFP: itr%d: exceptions=%08x\n",
+ vecitr >> FPSCR_LENGTH_BIT, except);
+
+ exceptions |= except;
+
+ /*
+ * CHECK: It appears to be undefined whether we stop when
+ * we encounter an exception. We continue.
+ */
+ dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
+ sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
+ if (FREG_BANK(sm) != 0)
+ sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7);
+ }
+ return exceptions;
+
+invalid:
+ return (u32)-1;
}
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 01d4f0af..25c78d33 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -5,12 +5,14 @@
#include "common/common_types.h"
#include "core/core.h"
-#include "core/hw/hw.h"
+
+#include "core/settings.h"
#include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/interpreter/arm_interpreter.h"
-
+#include "core/arm/dyncom/arm_dyncom.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/thread.h"
+#include "core/hw/hw.h"
namespace Core {
@@ -48,9 +50,18 @@ int Init() {
NOTICE_LOG(MASTER_LOG, "initialized OK");
g_disasm = new ARM_Disasm();
- g_app_core = new ARM_Interpreter();
g_sys_core = new ARM_Interpreter();
+ switch (Settings::values.cpu_core) {
+ case CPU_FastInterpreter:
+ g_app_core = new ARM_DynCom();
+ break;
+ case CPU_Interpreter:
+ default:
+ g_app_core = new ARM_Interpreter();
+ break;
+ }
+
g_last_ticks = Core::g_app_core->GetTicks();
return 0;
diff --git a/src/core/core.h b/src/core/core.h
index 87da252b..850bb0ab 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -11,6 +11,11 @@
namespace Core {
+enum CPUCore {
+ CPU_Interpreter,
+ CPU_FastInterpreter
+};
+
extern ARM_Interface* g_app_core; ///< ARM11 application core
extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core
@@ -21,13 +26,13 @@ void Start();
/**
* Run the core CPU loop
- * This function loops for 100 instructions in the CPU before trying to update hardware. This is a
- * little bit faster than SingleStep, and should be pretty much equivalent. The number of
- * instructions chosen is fairly arbitrary, however a large number will more drastically affect the
- * frequency of GSP interrupts and likely break things. The point of this is to just loop in the CPU
- * for more than 1 instruction to reduce overhead and make it a little bit faster...
+ * This function runs the core for the specified number of CPU instructions before trying to update
+ * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not
+ * required to do a full dispatch with each instruction. NOTE: the number of instructions requested
+ * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is
+ * requested (e.g. on a thread switch).
*/
-void RunLoop(int tight_loop=100);
+void RunLoop(int tight_loop=1000);
/// Step the CPU one instruction
void SingleStep();
diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h
index 560db6de..38145eed 100644
--- a/src/core/file_sys/archive.h
+++ b/src/core/file_sys/archive.h
@@ -7,11 +7,13 @@
#include <memory>
#include "common/common_types.h"
+#include "common/string_util.h"
#include "common/bit_field.h"
#include "core/file_sys/file.h"
#include "core/file_sys/directory.h"
+#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -19,6 +21,15 @@
namespace FileSys {
+// Path string type
+enum LowPathType : u32 {
+ Invalid = 0,
+ Empty = 1,
+ Binary = 2,
+ Char = 3,
+ Wchar = 4
+};
+
union Mode {
u32 hex;
BitField<0, 1, u32> read_flag;
@@ -26,6 +37,94 @@ union Mode {
BitField<2, 1, u32> create_flag;
};
+class Path {
+public:
+
+ Path():
+ type(Invalid)
+ {
+ }
+
+ Path(LowPathType type, u32 size, u32 pointer):
+ type(type)
+ {
+ switch (type) {
+ case Binary:
+ {
+ u8* data = Memory::GetPointer(pointer);
+ binary = std::vector<u8>(data, data + size);
+ break;
+ }
+ case Char:
+ {
+ const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
+ string = std::string(data, size - 1); // Data is always null-terminated.
+ break;
+ }
+ case Wchar:
+ {
+ const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer));
+ u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
+ break;
+ }
+ }
+ }
+
+ LowPathType GetType() const {
+ return type;
+ }
+
+ const std::string AsString() const {
+ switch (GetType()) {
+ case Char:
+ return string;
+ case Wchar:
+ return Common::UTF16ToUTF8(u16str);
+ case Empty:
+ return {};
+ default:
+ ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!");
+ return {};
+ }
+ }
+
+ const std::u16string AsU16Str() const {
+ switch (GetType()) {
+ case Char:
+ return Common::UTF8ToUTF16(string);
+ case Wchar:
+ return u16str;
+ case Empty:
+ return {};
+ default:
+ ERROR_LOG(KERNEL, "LowPathType cannot be converted to u16string!");
+ return {};
+ }
+ }
+
+ const std::vector<u8> AsBinary() const {
+ switch (GetType()) {
+ case Binary:
+ return binary;
+ case Char:
+ return std::vector<u8>(string.begin(), string.end());
+ case Wchar:
+ return std::vector<u8>(u16str.begin(), u16str.end());
+ case Empty:
+ return {};
+ default:
+ ERROR_LOG(KERNEL, "LowPathType cannot be converted to binary!");
+ return {};
+ }
+ }
+
+private:
+ LowPathType type;
+ std::vector<u8> binary;
+ std::string string;
+ std::u16string u16str;
+};
+
class Archive : NonCopyable {
public:
/// Supported archive types
@@ -57,6 +156,13 @@ public:
virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0;
/**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+ virtual bool CreateDirectory(const std::string& path) const = 0;
+
+ /**
* Open a directory specified by its path
* @param path Path relative to the archive
* @return Opened directory, or nullptr
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index 9bab3471..cc759faa 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -34,6 +34,16 @@ std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mod
}
/**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+bool Archive_RomFS::CreateDirectory(const std::string& path) const {
+ ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS.");
+ return false;
+};
+
+/**
* Open a directory specified by its path
* @param path Path relative to the archive
* @return Opened directory, or nullptr
@@ -50,7 +60,7 @@ std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path)
* @return Number of bytes read
*/
size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {
- DEBUG_LOG(FILESYS, "called offset=%d, length=%d", offset, length);
+ DEBUG_LOG(FILESYS, "called offset=%llu, length=%d", offset, length);
memcpy(buffer, &raw_data[(u32)offset], length);
return length;
}
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index fcdefa95..ae2344e8 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -37,6 +37,13 @@ public:
std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override;
/**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+ bool CreateDirectory(const std::string& path) const override;
+
+ /**
* Open a directory specified by its path
* @param path Path relative to the archive
* @return Opened directory, or nullptr
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 0b647f7d..66931e93 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -58,6 +58,15 @@ std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode
}
/**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+bool Archive_SDMC::CreateDirectory(const std::string& path) const {
+ return FileUtil::CreateDir(GetMountPoint() + path);
+}
+
+/**
* Open a directory specified by its path
* @param path Path relative to the archive
* @return Opened directory, or nullptr
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index f68648e6..0e059b63 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -41,6 +41,13 @@ public:
std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override;
/**
+ * Create a directory specified by its path
+ * @param path Path relative to the archive
+ * @return Whether the directory could be created
+ */
+ bool CreateDirectory(const std::string& path) const override;
+
+ /**
* Open a directory specified by its path
* @param path Path relative to the archive
* @return Opened directory, or nullptr
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp
index 36951564..fd558def 100644
--- a/src/core/file_sys/directory_sdmc.cpp
+++ b/src/core/file_sys/directory_sdmc.cpp
@@ -42,7 +42,7 @@ u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
const std::string& filename = file.virtualName;
Entry& entry = entries[entries_read];
- WARN_LOG(FILESYS, "File %s: size=%d dir=%d", filename.c_str(), file.size, file.isDirectory);
+ WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
// TODO(Link Mauve): use a proper conversion to UTF-16.
for (int j = 0; j < FILENAME_LENGTH; ++j) {
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 174d4cd6..2b21657d 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -17,11 +17,11 @@ namespace Kernel {
class AddressArbiter : public Object {
public:
- std::string GetTypeName() const { return "Arbiter"; }
- std::string GetName() const { return name; }
+ std::string GetTypeName() const override { return "Arbiter"; }
+ std::string GetName() const override { return name; }
static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; }
- Kernel::HandleType GetHandleType() const { return HandleType::AddressArbiter; }
+ Kernel::HandleType GetHandleType() const override { return HandleType::AddressArbiter; }
std::string name; ///< Name of address arbiter object (optional)
@@ -30,7 +30,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
index 86aba748..764082d7 100644
--- a/src/core/hle/kernel/archive.cpp
+++ b/src/core/hle/kernel/archive.cpp
@@ -42,11 +42,11 @@ enum class DirectoryCommand : u32 {
class Archive : public Object {
public:
- std::string GetTypeName() const { return "Archive"; }
- std::string GetName() const { return name; }
+ std::string GetTypeName() const override { return "Archive"; }
+ std::string GetName() const override { return name; }
static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; }
- Kernel::HandleType GetHandleType() const { return HandleType::Archive; }
+ Kernel::HandleType GetHandleType() const override { return HandleType::Archive; }
std::string name; ///< Name of archive (optional)
FileSys::Archive* backend; ///< Archive backend interface
@@ -56,7 +56,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result SyncRequest(bool* wait) {
+ Result SyncRequest(bool* wait) override {
u32* cmd_buff = Service::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
@@ -119,7 +119,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
@@ -128,11 +128,11 @@ public:
class File : public Object {
public:
- std::string GetTypeName() const { return "File"; }
- std::string GetName() const { return path; }
+ std::string GetTypeName() const override { return "File"; }
+ std::string GetName() const override { return path; }
static Kernel::HandleType GetStaticHandleType() { return HandleType::File; }
- Kernel::HandleType GetHandleType() const { return HandleType::File; }
+ Kernel::HandleType GetHandleType() const override { return HandleType::File; }
std::string path; ///< Path of the file
std::unique_ptr<FileSys::File> backend; ///< File backend interface
@@ -142,7 +142,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result SyncRequest(bool* wait) {
+ Result SyncRequest(bool* wait) override {
u32* cmd_buff = Service::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
switch (cmd) {
@@ -153,7 +153,7 @@ public:
u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
u32 length = cmd_buff[3];
u32 address = cmd_buff[5];
- DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%x length=%d address=0x%x",
+ DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%llx length=%d address=0x%x",
GetTypeName().c_str(), GetName().c_str(), offset, length, address);
cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
break;
@@ -166,7 +166,7 @@ public:
u32 length = cmd_buff[3];
u32 flush = cmd_buff[4];
u32 address = cmd_buff[6];
- DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%x length=%d address=0x%x, flush=0x%x",
+ DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
break;
@@ -184,7 +184,7 @@ public:
case FileCommand::SetSize:
{
u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
- DEBUG_LOG(KERNEL, "SetSize %s %s size=%d", GetTypeName().c_str(), GetName().c_str(), size);
+ DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size);
backend->SetSize(size);
break;
}
@@ -211,7 +211,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
@@ -220,11 +220,11 @@ public:
class Directory : public Object {
public:
- std::string GetTypeName() const { return "Directory"; }
- std::string GetName() const { return path; }
+ std::string GetTypeName() const override { return "Directory"; }
+ std::string GetName() const override { return path; }
static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; }
- Kernel::HandleType GetHandleType() const { return HandleType::Directory; }
+ Kernel::HandleType GetHandleType() const override { return HandleType::Directory; }
std::string path; ///< Path of the directory
std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
@@ -234,7 +234,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result SyncRequest(bool* wait) {
+ Result SyncRequest(bool* wait) override {
u32* cmd_buff = Service::GetCommandBuffer();
DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
switch (cmd) {
@@ -274,7 +274,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
@@ -381,6 +381,21 @@ Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const
}
/**
+ * Create a Directory from an Archive
+ * @param archive_handle Handle to an open Archive object
+ * @param path Path to the Directory inside of the Archive
+ * @return Opened Directory object
+ */
+Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) {
+ Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
+ if (archive == nullptr)
+ return -1;
+ if (archive->backend->CreateDirectory(path))
+ return 0;
+ return -1;
+}
+
+/**
* Open a Directory from an Archive
* @param archive_handle Handle to an open Archive object
* @param path Path to the Directory inside of the Archive
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h
index 593861f8..0230996b 100644
--- a/src/core/hle/kernel/archive.h
+++ b/src/core/hle/kernel/archive.h
@@ -43,7 +43,15 @@ Handle CreateArchive(FileSys::Archive* backend, const std::string& name);
* @param mode Mode under which to open the File
* @return Opened File object
*/
-Handle OpenFileFromArchive(Handle handle, const std::string& name, const FileSys::Mode mode);
+Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode);
+
+/**
+ * Create a Directory from an Archive
+ * @param archive_handle Handle to an open Archive object
+ * @param path Path to the Directory inside of the Archive
+ * @return Whether creation of directory succeeded
+ */
+Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name);
/**
* Open a Directory from an Archive
@@ -51,7 +59,7 @@ Handle OpenFileFromArchive(Handle handle, const std::string& name, const FileSys
* @param path Path to the Directory inside of the Archive
* @return Opened Directory object
*/
-Handle OpenDirectoryFromArchive(Handle handle, const std::string& name);
+Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name);
/// Initialize archives
void ArchiveInit();
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 64f6a964..45ed79be 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -16,11 +16,11 @@ namespace Kernel {
class Event : public Object {
public:
- std::string GetTypeName() const { return "Event"; }
- std::string GetName() const { return name; }
+ std::string GetTypeName() const override { return "Event"; }
+ std::string GetName() const override { return name; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Event; }
ResetType intitial_reset_type; ///< ResetType specified at Event initialization
ResetType reset_type; ///< Current ResetType
@@ -35,7 +35,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
*wait = locked;
if (locked) {
Handle thread = GetCurrentThreadHandle();
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 5d7d65dd..fcfd061a 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -15,11 +15,11 @@ namespace Kernel {
class Mutex : public Object {
public:
- std::string GetTypeName() const { return "Mutex"; }
- std::string GetName() const { return name; }
+ std::string GetTypeName() const override { return "Mutex"; }
+ std::string GetName() const override { return name; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; }
bool initial_locked; ///< Initial lock state when mutex was created
bool locked; ///< Current locked state
@@ -32,7 +32,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result SyncRequest(bool* wait) {
+ Result SyncRequest(bool* wait) override {
// TODO(bunnei): ImplementMe
locked = true;
return 0;
@@ -43,7 +43,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
*wait = locked;
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 2a6a483a..f538c655 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -11,17 +11,17 @@ namespace Kernel {
class SharedMemory : public Object {
public:
- std::string GetTypeName() const { return "SharedMemory"; }
+ std::string GetTypeName() const override { return "SharedMemory"; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; }
/**
* Wait for kernel object to synchronize
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
return 0;
@@ -72,7 +72,7 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!",
- handle);
+ handle, address);
return -1;
}
SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle);
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 33c0b2a4..e15590c4 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -21,11 +21,11 @@ namespace Kernel {
class Thread : public Kernel::Object {
public:
- std::string GetName() const { return name; }
- std::string GetTypeName() const { return "Thread"; }
+ std::string GetName() const override { return name; }
+ std::string GetTypeName() const override { return "Thread"; }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; }
inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
@@ -38,7 +38,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
if (status != THREADSTATUS_DORMANT) {
Handle thread = GetCurrentThreadHandle();
if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
new file mode 100644
index 00000000..b39603bd
--- /dev/null
+++ b/src/core/hle/service/ac_u.cpp
@@ -0,0 +1,44 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/ac_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace AC_U
+
+namespace AC_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, nullptr, "CreateDefaultConfig"},
+ {0x00040006, nullptr, "ConnectAsync"},
+ {0x00050002, nullptr, "GetConnectResult"},
+ {0x00080004, nullptr, "CloseAsync"},
+ {0x00090002, nullptr, "GetCloseResult"},
+ {0x000A0000, nullptr, "GetLastErrorCode"},
+ {0x000D0000, nullptr, "GetWifiStatus"},
+ {0x000E0042, nullptr, "GetCurrentAPInfo"},
+ {0x00100042, nullptr, "GetCurrentNZoneInfo"},
+ {0x00110042, nullptr, "GetNZoneApNumService"},
+ {0x00240042, nullptr, "AddDenyApType "},
+ {0x00270002, nullptr, "GetInfraPriority "},
+ {0x002D0082, nullptr, "SetRequestEulaVersion"},
+ {0x00300004, nullptr, "RegisterDisconnectEvent"},
+ {0x003C0042, nullptr, "GetAPSSIDList"},
+ {0x003E0042, nullptr, "IsConnected "},
+ {0x00400042, nullptr, "SetClientVersion"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/ac_u.h b/src/core/hle/service/ac_u.h
new file mode 100644
index 00000000..3c5958d2
--- /dev/null
+++ b/src/core/hle/service/ac_u.h
@@ -0,0 +1,29 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace AC_U
+
+// socket service "ac:u"
+
+namespace AC_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "ac:u";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt_u.cpp
index 3753f110..4f41ec5f 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt_u.cpp
@@ -8,13 +8,15 @@
#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
-#include "core/hle/service/apt.h"
+#include "apt_u.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace APT_U
namespace APT_U {
+static Handle lock_handle = 0;
+
/// Signals used by APT functions
enum class SignalType : u32 {
None = 0x0,
@@ -32,15 +34,32 @@ void Initialize(Service::Interface* self) {
Kernel::SetEventLocked(cmd_buff[3], true);
Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event
+ _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock");
+ Kernel::ReleaseMutex(lock_handle);
+
cmd_buff[1] = 0; // No error
+
DEBUG_LOG(KERNEL, "called");
}
void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
+
+ if (0 == lock_handle) {
+ // TODO(bunnei): Verify if this is created here or at application boot?
+ lock_handle = Kernel::CreateMutex(false, "APT_U:Lock");
+ Kernel::ReleaseMutex(lock_handle);
+ }
cmd_buff[1] = 0; // No error
- cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock");
+
+ // Not sure what these parameters are used for, but retail apps check that they are 0 after
+ // GetLockHandle has been called.
+ cmd_buff[2] = 0;
+ cmd_buff[3] = 0;
+ cmd_buff[4] = 0;
+
+ cmd_buff[5] = lock_handle;
DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]);
}
@@ -59,6 +78,25 @@ void InquireNotification(Service::Interface* self) {
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id);
}
+/**
+ * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state,
+ * from the source process which set the parameters. Once finished, NS will clear a flag in the NS
+ * state so that this command will return an error if this command is used again if parameters were
+ * not set again. This is called when the second Initialize event is triggered. It returns a signal
+ * type indicating why it was triggered.
+ * Inputs:
+ * 1 : AppID
+ * 2 : Parameter buffer size, max size is 0x1000
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Unknown, for now assume AppID of the process which sent these parameters
+ * 3 : Unknown, for now assume Signal type
+ * 4 : Actual parameter buffer size, this is <= to the the input size
+ * 5 : Value
+ * 6 : Handle from the source process which set the parameters, likely used for shared memory
+ * 7 : Size
+ * 8 : Output parameter buffer ptr
+ */
void ReceiveParameter(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 app_id = cmd_buff[1];
@@ -66,7 +104,7 @@ void ReceiveParameter(Service::Interface* self) {
cmd_buff[1] = 0; // No error
cmd_buff[2] = 0;
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
- cmd_buff[4] = 0x10;
+ cmd_buff[4] = 0x10; // Parameter buffer size (16)
cmd_buff[5] = 0;
cmd_buff[6] = 0;
cmd_buff[7] = 0;
@@ -74,35 +112,66 @@ void ReceiveParameter(Service::Interface* self) {
}
/**
-* APT_U::GlanceParameter service function
-* Inputs:
-* 1 : AppID
-* 2 : Parameter buffer size, max size is 0x1000
-* Outputs:
-* 1 : Result of function, 0 on success, otherwise error code
-* 2 : Unknown, for now assume AppID of the process which sent these parameters
-* 3 : Unknown, for now assume Signal type
-* 4 : Actual parameter buffer size, this is <= to the the input size
-* 5 : Value
-* 6 : Handle from the source process which set the parameters, likely used for shared memory
-* 7 : Size
-* 8 : Output parameter buffer ptr
-*/
+ * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter
+ * (except for the word value prior to the output handle), except this will not clear the flag
+ * (except when responseword[3]==8 || responseword[3]==9) in NS state.
+ * Inputs:
+ * 1 : AppID
+ * 2 : Parameter buffer size, max size is 0x1000
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Unknown, for now assume AppID of the process which sent these parameters
+ * 3 : Unknown, for now assume Signal type
+ * 4 : Actual parameter buffer size, this is <= to the the input size
+ * 5 : Value
+ * 6 : Handle from the source process which set the parameters, likely used for shared memory
+ * 7 : Size
+ * 8 : Output parameter buffer ptr
+ */
void GlanceParameter(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 app_id = cmd_buff[1];
u32 buffer_size = cmd_buff[2];
+
cmd_buff[1] = 0; // No error
cmd_buff[2] = 0;
cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
- cmd_buff[4] = 0;
+ cmd_buff[4] = 0x10; // Parameter buffer size (16)
cmd_buff[5] = 0;
cmd_buff[6] = 0;
cmd_buff[7] = 0;
- cmd_buff[8] = 0;
+
WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
}
+/**
+ * APT_U::AppletUtility service function
+ * Inputs:
+ * 1 : Unknown, but clearly used for something
+ * 2 : Buffer 1 size (purpose is unknown)
+ * 3 : Buffer 2 size (purpose is unknown)
+ * 5 : Buffer 1 address (purpose is unknown)
+ * 65 : Buffer 2 address (purpose is unknown)
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void AppletUtility(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ // These are from 3dbrew - I'm not really sure what they're used for.
+ u32 unk = cmd_buff[1];
+ u32 buffer1_size = cmd_buff[2];
+ u32 buffer2_size = cmd_buff[3];
+ u32 buffer1_addr = cmd_buff[5];
+ u32 buffer2_addr = cmd_buff[65];
+
+ cmd_buff[1] = 0; // No error
+
+ WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, "
+ "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size,
+ buffer1_addr, buffer2_addr);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, GetLockHandle, "GetLockHandle"},
{0x00020080, Initialize, "Initialize"},
@@ -178,7 +247,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00480100, nullptr, "GetProgramInfo"},
{0x00490180, nullptr, "Reboot"},
{0x004A0040, nullptr, "GetCaptureInfo"},
- {0x004B00C2, nullptr, "AppletUtility"},
+ {0x004B00C2, AppletUtility, "AppletUtility"},
{0x004C0000, nullptr, "SetFatalErrDispMode"},
{0x004D0080, nullptr, "GetAppletProgramInfo"},
{0x004E0000, nullptr, "HardwareResetAsync"},
@@ -191,6 +260,8 @@ const Interface::FunctionInfo FunctionTable[] = {
Interface::Interface() {
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+
+ lock_handle = 0;
}
Interface::~Interface() {
diff --git a/src/core/hle/service/apt.h b/src/core/hle/service/apt_u.h
index 4c7dd07e..5af39e08 100644
--- a/src/core/hle/service/apt.h
+++ b/src/core/hle/service/apt_u.h
@@ -29,7 +29,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "APT:U";
}
};
diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp
new file mode 100644
index 00000000..822b0e2b
--- /dev/null
+++ b/src/core/hle/service/cfg_u.cpp
@@ -0,0 +1,36 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/cfg_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace CFG_U
+
+namespace CFG_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010082, nullptr, "GetConfigInfoBlk2"},
+ {0x00020000, nullptr, "SecureInfoGetRegion"},
+ {0x00030000, nullptr, "GenHashConsoleUnique"},
+ {0x00040000, nullptr, "GetRegionCanadaUSA"},
+ {0x00050000, nullptr, "GetSystemModel"},
+ {0x00060000, nullptr, "GetModelNintendo2DS"},
+ {0x00070040, nullptr, "unknown"},
+ {0x00080080, nullptr, "unknown"},
+ {0x00090080, nullptr, "GetCountryCodeString"},
+ {0x000A0040, nullptr, "GetCountryCodeID"},
+};
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/cfg_u.h b/src/core/hle/service/cfg_u.h
new file mode 100644
index 00000000..7525bd7c
--- /dev/null
+++ b/src/core/hle/service/cfg_u.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace CFG_U
+
+namespace CFG_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "cfg:u";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
new file mode 100644
index 00000000..9e84ac93
--- /dev/null
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -0,0 +1,52 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/dsp_dsp.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace DSP_DSP
+
+namespace DSP_DSP {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010040, nullptr, "RecvData"},
+ {0x00020040, nullptr, "RecvDataIsReady"},
+ {0x00030080, nullptr, "SendData"},
+ {0x00040040, nullptr, "SendDataIsEmpty"},
+ {0x00070040, nullptr, "WriteReg0x10"},
+ {0x00080000, nullptr, "GetSemaphore"},
+ {0x00090040, nullptr, "ClearSemaphore"},
+ {0x000B0000, nullptr, "CheckSemaphoreRequest"},
+ {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"},
+ {0x000D0082, nullptr, "WriteProcessPipe"},
+ {0x001000C0, nullptr, "ReadPipeIfPossible"},
+ {0x001100C2, nullptr, "LoadComponent"},
+ {0x00120000, nullptr, "UnloadComponent"},
+ {0x00130082, nullptr, "FlushDataCache"},
+ {0x00140082, nullptr, "InvalidateDCache "},
+ {0x00150082, nullptr, "RegisterInterruptEvents"},
+ {0x00160000, nullptr, "GetSemaphoreEventHandle"},
+ {0x00170040, nullptr, "SetSemaphoreMask"},
+ {0x00180040, nullptr, "GetPhysicalAddress"},
+ {0x00190040, nullptr, "GetVirtualAddress" },
+ {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
+ {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
+ {0x001C0082, nullptr, "SetIirFilterEQ"},
+ {0x001F0000, nullptr, "GetHeadphoneStatus"},
+ {0x00210000, nullptr, "GetIsDspOccupied"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
new file mode 100644
index 00000000..c439ed26
--- /dev/null
+++ b/src/core/hle/service/dsp_dsp.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace DSP_DSP
+
+namespace DSP_DSP {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "dsp:DSP";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
new file mode 100644
index 00000000..917b2f8c
--- /dev/null
+++ b/src/core/hle/service/err_f.cpp
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/err_f.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace ERR_F
+
+namespace ERR_F {
+
+ const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010800, nullptr, "ThrowFatalError"}
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Interface class
+
+ Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+ }
+
+ Interface::~Interface() {
+ }
+
+} // namespace
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
new file mode 100644
index 00000000..5da66326
--- /dev/null
+++ b/src/core/hle/service/err_f.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace ERR_F
+
+namespace ERR_F {
+
+ class Interface : public Service::Interface {
+ public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "err:f";
+ }
+ };
+
+} // namespace
diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd_u.cpp
new file mode 100644
index 00000000..58023e53
--- /dev/null
+++ b/src/core/hle/service/frd_u.cpp
@@ -0,0 +1,35 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/frd_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace FRD_U
+
+namespace FRD_U {
+
+ const Interface::FunctionInfo FunctionTable[] = {
+ {0x00050000, nullptr, "GetFriendKey"},
+ {0x00080000, nullptr, "GetMyPresence"},
+ {0x00100040, nullptr, "GetPassword"},
+ {0x00190042, nullptr, "GetFriendFavoriteGame"},
+ {0x001A00C4, nullptr, "GetFriendInfo"},
+ {0x001B0080, nullptr, "IsOnFriendList"},
+ {0x001C0042, nullptr, "DecodeLocalFriendCode"},
+ {0x001D0002, nullptr, "SetCurrentlyPlayingText"},
+ {0x00320042, nullptr, "SetClientSdkVersion"}
+ };
+ ////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Interface class
+
+ Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+ }
+
+ Interface::~Interface() {
+ }
+
+} // namespace
diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h
new file mode 100644
index 00000000..9df8a815
--- /dev/null
+++ b/src/core/hle/service/frd_u.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace FRD_U
+
+namespace FRD_U {
+
+ class Interface : public Service::Interface {
+ public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "frd:u";
+ }
+ };
+
+} // namespace
diff --git a/src/core/hle/service/fs.cpp b/src/core/hle/service/fs_user.cpp
index 662c4f24..9dc83291 100644
--- a/src/core/hle/service/fs.cpp
+++ b/src/core/hle/service/fs_user.cpp
@@ -4,7 +4,9 @@
#include "common/common.h"
-#include "core/hle/service/fs.h"
+#include "fs_user.h"
+#include "common/string_util.h"
+#include "core/settings.h"
#include "core/hle/kernel/archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -12,20 +14,6 @@
namespace FS_User {
-// Command to access archive file
-enum class LowPathType : u32 {
- Invalid = 0,
- Empty = 1,
- Binary = 2,
- Char = 3,
- Wchar = 4
-};
-
-std::string GetStringFromCmdBuff(const u32 pointer, const u32 size) {
- auto data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
- return std::string(data, size - 1);
-}
-
// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it
// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make
// sure we don't mislead the application into thinking something worked.
@@ -43,32 +31,36 @@ void Initialize(Service::Interface* self) {
void OpenFile(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
- u32 transaction = cmd_buff[1];
// TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
// 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
- LowPathType type = static_cast<LowPathType>(cmd_buff[4]);
- u32 size = cmd_buff[5];
+ auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
+ u32 filename_size = cmd_buff[5];
FileSys::Mode mode; mode.hex = cmd_buff[6];
- u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
- u32 pointer = cmd_buff[9];
-
- if (type != LowPathType::Char) {
- ERROR_LOG(KERNEL, "file LowPath type other than char is currently unsupported");
- cmd_buff[1] = -1;
+ u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
+ u32 filename_ptr = cmd_buff[9];
+
+ FileSys::Path file_path(filename_type, filename_size, filename_ptr);
+ std::string file_string;
+ switch (file_path.GetType()) {
+ case FileSys::Char:
+ case FileSys::Wchar:
+ file_string = file_path.AsString();
+ break;
+ default:
+ WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead");
return;
}
- std::string file_name = GetStringFromCmdBuff(pointer, size);
-
- DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", type, size, mode, attributes, file_name.c_str());
+ DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s",
+ filename_type, filename_size, mode, attributes, file_string.c_str());
- Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_name, mode);
+ Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode);
if (handle) {
cmd_buff[1] = 0;
cmd_buff[3] = handle;
} else {
- ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_name.c_str());
+ ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str());
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
cmd_buff[1] = -1;
}
@@ -79,31 +71,25 @@ void OpenFile(Service::Interface* self) {
void OpenFileDirectly(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
- u32 transaction = cmd_buff[1];
- auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
- LowPathType archive_type = static_cast<LowPathType>(cmd_buff[3]);
- u32 archive_size = cmd_buff[4];
- LowPathType file_type = static_cast<LowPathType>(cmd_buff[5]);
- u32 size = cmd_buff[6];
+ auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
+ auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
+ u32 archivename_size = cmd_buff[4];
+ auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]);
+ u32 filename_size = cmd_buff[6];
FileSys::Mode mode; mode.hex = cmd_buff[7];
- u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
- u32 archive_pointer = cmd_buff[10];
- u32 pointer = cmd_buff[12];
+ u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
+ u32 archivename_ptr = cmd_buff[10];
+ u32 filename_ptr = cmd_buff[12];
- if (archive_type != LowPathType::Empty) {
+ DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d file_type=%d file_size=%d file_mode=%d file_attrs=%d",
+ archivename_type, archivename_size, filename_type, filename_size, mode, attributes);
+
+ if (archivename_type != FileSys::Empty) {
ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
cmd_buff[1] = -1;
return;
}
- std::string archive_name = GetStringFromCmdBuff(archive_pointer, archive_size);
- std::string file_name = GetStringFromCmdBuff(pointer, size);
-
- DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d archive_data=%s"
- "file_type=%d file_size=%d file_mode=%d file_attrs=%d file_data=%s",
- archive_type, archive_size, archive_name.c_str(),
- file_type, size, mode, attributes, file_name.c_str());
-
// TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it.
Handle archive_handle = Kernel::OpenArchive(archive_id);
if (archive_handle) {
@@ -111,23 +97,30 @@ void OpenFileDirectly(Service::Interface* self) {
// cmd_buff[2] isn't used according to 3dmoo's implementation.
cmd_buff[3] = archive_handle;
} else {
- ERROR_LOG(KERNEL, "failed to get a handle for archive %s", archive_name.c_str());
+ ERROR_LOG(KERNEL, "failed to get a handle for archive");
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
cmd_buff[1] = -1;
return;
}
- if (file_type != LowPathType::Char) {
- WARN_LOG(KERNEL, "file LowPath type other than char is currently unsupported; returning archive handle instead");
+ FileSys::Path file_path(filename_type, filename_size, filename_ptr);
+ std::string file_string;
+ switch (file_path.GetType()) {
+ case FileSys::Char:
+ case FileSys::Wchar:
+ file_string = file_path.AsString();
+ break;
+ default:
+ WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead");
return;
}
- Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_name, mode);
+ Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode);
if (handle) {
cmd_buff[1] = 0;
cmd_buff[3] = handle;
} else {
- ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_name.c_str());
+ ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str());
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
cmd_buff[1] = -1;
}
@@ -135,32 +128,76 @@ void OpenFileDirectly(Service::Interface* self) {
DEBUG_LOG(KERNEL, "called");
}
+/*
+ * FS_User::CreateDirectory service function
+ * Inputs:
+ * 2 : Archive handle lower word
+ * 3 : Archive handle upper word
+ * 4 : Directory path string type
+ * 5 : Directory path string size
+ * 8 : Directory path string data
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void CreateDirectory(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to
+ // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
+ Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
+ auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
+ u32 dirname_size = cmd_buff[5];
+ u32 dirname_ptr = cmd_buff[8];
+
+ FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
+ std::string dir_string;
+ switch (dir_path.GetType()) {
+ case FileSys::Char:
+ case FileSys::Wchar:
+ dir_string = dir_path.AsString();
+ break;
+ default:
+ cmd_buff[1] = -1;
+ return;
+ }
+
+ DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str());
+
+ cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_string);
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
void OpenDirectory(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
// TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
// 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
Handle archive_handle = static_cast<Handle>(cmd_buff[2]);
- LowPathType type = static_cast<LowPathType>(cmd_buff[3]);
- u32 size = cmd_buff[4];
- u32 pointer = cmd_buff[6];
-
- if (type != LowPathType::Char) {
- ERROR_LOG(KERNEL, "directory LowPath type other than char is currently unsupported");
+ auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
+ u32 dirname_size = cmd_buff[4];
+ u32 dirname_ptr = cmd_buff[6];
+
+ FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
+ std::string dir_string;
+ switch (dir_path.GetType()) {
+ case FileSys::Char:
+ case FileSys::Wchar:
+ dir_string = dir_path.AsString();
+ break;
+ default:
cmd_buff[1] = -1;
return;
}
- std::string dir_name = GetStringFromCmdBuff(pointer, size);
+ DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str());
- DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", type, size, dir_name.c_str());
-
- Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_name);
+ Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_string);
if (handle) {
cmd_buff[1] = 0;
cmd_buff[3] = handle;
} else {
- ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_name.c_str());
+ ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str());
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
cmd_buff[1] = -1;
}
@@ -171,28 +208,26 @@ void OpenDirectory(Service::Interface* self) {
void OpenArchive(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
- auto arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]);
- LowPathType type = static_cast<LowPathType>(cmd_buff[2]);
- u32 size = cmd_buff[3];
- u32 pointer = cmd_buff[5];
+ auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]);
+ auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
+ u32 archivename_size = cmd_buff[3];
+ u32 archivename_ptr = cmd_buff[5];
+
+ DEBUG_LOG(KERNEL, "type=%d size=%d", archivename_type, archivename_size);
- if (type != LowPathType::Empty) {
+ if (archivename_type != FileSys::Empty) {
ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
cmd_buff[1] = -1;
return;
}
- std::string archive_name = GetStringFromCmdBuff(pointer, size);
-
- DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", type, size, archive_name.c_str());
-
- Handle handle = Kernel::OpenArchive(arch_id);
+ Handle handle = Kernel::OpenArchive(archive_id);
if (handle) {
cmd_buff[1] = 0;
// cmd_buff[2] isn't used according to 3dmoo's implementation.
cmd_buff[3] = handle;
} else {
- ERROR_LOG(KERNEL, "failed to get a handle for archive %s", archive_name.c_str());
+ ERROR_LOG(KERNEL, "failed to get a handle for archive");
// TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
cmd_buff[1] = -1;
}
@@ -200,6 +235,21 @@ void OpenArchive(Service::Interface* self) {
DEBUG_LOG(KERNEL, "called");
}
+/*
+* FS_User::IsSdmcDetected service function
+* Outputs:
+* 1 : Result of function, 0 on success, otherwise error code
+* 2 : Whether the Sdmc could be detected
+*/
+void IsSdmcDetected(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ cmd_buff[1] = 0;
+ cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
+
+ DEBUG_LOG(KERNEL, "called");
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x000100C6, nullptr, "Dummy1"},
{0x040100C4, nullptr, "Control"},
@@ -211,7 +261,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08060142, nullptr, "DeleteDirectory"},
{0x08070142, nullptr, "DeleteDirectoryRecursively"},
{0x08080202, nullptr, "CreateFile"},
- {0x08090182, nullptr, "CreateDirectory"},
+ {0x08090182, CreateDirectory, "CreateDirectory"},
{0x080A0244, nullptr, "RenameDirectory"},
{0x080B0102, OpenDirectory, "OpenDirectory"},
{0x080C00C2, OpenArchive, "OpenArchive"},
@@ -225,7 +275,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08140000, nullptr, "GetSdmcArchiveResource"},
{0x08150000, nullptr, "GetNandArchiveResource"},
{0x08160000, nullptr, "GetSdmcFatfsErro"},
- {0x08170000, nullptr, "IsSdmcDetected"},
+ {0x08170000, IsSdmcDetected, "IsSdmcDetected"},
{0x08180000, nullptr, "IsSdmcWritable"},
{0x08190042, nullptr, "GetSdmcCid"},
{0x081A0042, nullptr, "GetNandCid"},
diff --git a/src/core/hle/service/fs.h b/src/core/hle/service/fs_user.h
index 36f3697d..00538254 100644
--- a/src/core/hle/service/fs.h
+++ b/src/core/hle/service/fs_user.h
@@ -23,7 +23,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "fs:USER";
}
};
diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp_gpu.cpp
index 614d9584..6119e630 100644
--- a/src/core/hle/service/gsp.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -9,7 +9,7 @@
#include "core/mem_map.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
-#include "core/hle/service/gsp.h"
+#include "gsp_gpu.h"
#include "core/hw/gpu.h"
#include "video_core/gpu_debugger.h"
diff --git a/src/core/hle/service/gsp.h b/src/core/hle/service/gsp_gpu.h
index a09d59db..177ce8da 100644
--- a/src/core/hle/service/gsp.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -167,7 +167,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "gsp::Gpu";
}
diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid_user.cpp
index b6ec1b8f..0eb32ba4 100644
--- a/src/core/hle/service/hid.cpp
+++ b/src/core/hle/service/hid_user.cpp
@@ -7,7 +7,7 @@
#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
-#include "core/hle/service/hid.h"
+#include "hid_user.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace HID_User
@@ -78,6 +78,10 @@ void PadButtonRelease(PadState pad_state) {
void PadUpdateComplete() {
PadData* pad_data = GetPadData();
+ if (pad_data == nullptr) {
+ return;
+ }
+
// Update PadData struct
pad_data->current_state.hex = next_state.hex;
pad_data->index = next_index;
diff --git a/src/core/hle/service/hid.h b/src/core/hle/service/hid_user.h
index a077e25c..9f6c4d5e 100644
--- a/src/core/hle/service/hid.h
+++ b/src/core/hle/service/hid_user.h
@@ -111,7 +111,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "hid:USER";
}
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
new file mode 100644
index 00000000..58051f13
--- /dev/null
+++ b/src/core/hle/service/mic_u.cpp
@@ -0,0 +1,43 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/mic_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace MIC_U
+
+namespace MIC_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010042, nullptr, "MapSharedMem"},
+ {0x00020000, nullptr, "UnmapSharedMem"},
+ {0x00030140, nullptr, "Initialize"},
+ {0x00040040, nullptr, "AdjustSampling"},
+ {0x00050000, nullptr, "StopSampling"},
+ {0x00060000, nullptr, "IsSampling"},
+ {0x00070000, nullptr, "GetEventHandle"},
+ {0x00080040, nullptr, "SetControl"},
+ {0x00090000, nullptr, "GetControl"},
+ {0x000A0040, nullptr, "SetBias"},
+ {0x000B0000, nullptr, "GetBias"},
+ {0x000C0042, nullptr, "size"},
+ {0x000D0040, nullptr, "SetClamp"},
+ {0x000E0000, nullptr, "GetClamp"},
+ {0x000F0040, nullptr, "unknown_input1"},
+ {0x00100040, nullptr, "unknown_input2"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h
new file mode 100644
index 00000000..72ba048e
--- /dev/null
+++ b/src/core/hle/service/mic_u.h
@@ -0,0 +1,29 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace MIC_U
+
+// mic service
+
+namespace MIC_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "mic:u";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/ndm.cpp b/src/core/hle/service/ndm_u.cpp
index f6af0a15..37c0661b 100644
--- a/src/core/hle/service/ndm.cpp
+++ b/src/core/hle/service/ndm_u.cpp
@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#include "core/hle/hle.h"
-#include "core/hle/service/ndm.h"
+#include "ndm_u.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace NDM_U
diff --git a/src/core/hle/service/ndm.h b/src/core/hle/service/ndm_u.h
index d5ec28f5..2ca9fcf2 100644
--- a/src/core/hle/service/ndm.h
+++ b/src/core/hle/service/ndm_u.h
@@ -24,7 +24,7 @@ public:
* Gets the string port name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "ndm:u";
}
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
new file mode 100644
index 00000000..14df86d8
--- /dev/null
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -0,0 +1,35 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/nwm_uds.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace NWM_UDS
+
+namespace NWM_UDS {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00030000, nullptr, "Shutdown"},
+ {0x000F0404, nullptr, "RecvBeaconBroadcastData"},
+ {0x00100042, nullptr, "SetBeaconAdditionalData"},
+ {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
+ {0x001B0302, nullptr, "Initialize"},
+ {0x001D0044, nullptr, "BeginHostingNetwork"},
+ {0x001E0084, nullptr, "ConnectToNetwork"},
+ {0x001F0006, nullptr, "DecryptBeaconData"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
new file mode 100644
index 00000000..a956ca81
--- /dev/null
+++ b/src/core/hle/service/nwm_uds.h
@@ -0,0 +1,29 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace NWM_UDS
+
+// local-WLAN service
+
+namespace NWM_UDS {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "nwm:UDS";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp
new file mode 100644
index 00000000..f6a14d50
--- /dev/null
+++ b/src/core/hle/service/ptm_u.cpp
@@ -0,0 +1,42 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/ptm_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace PTM_U
+
+namespace PTM_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010002, nullptr, "RegisterAlarmClient"},
+ {0x00020080, nullptr, "SetRtcAlarm"},
+ {0x00030000, nullptr, "GetRtcAlarm"},
+ {0x00040000, nullptr, "CancelRtcAlarm"},
+ {0x00050000, nullptr, "GetAdapterState"},
+ {0x00060000, nullptr, "GetShellState "},
+ {0x00070000, nullptr, "GetBatteryLevel"},
+ {0x00080000, nullptr, "GetBatteryChargeState"},
+ {0x00090000, nullptr, "GetPedometerState"},
+ {0x000A0042, nullptr, "GetStepHistoryEntry"},
+ {0x000B00C2, nullptr, "GetStepHistory "},
+ {0x000C0000, nullptr, "GetTotalStepCount "},
+ {0x000D0040, nullptr, "SetPedometerRecordingMode"},
+ {0x000E0000, nullptr, "GetPedometerRecordingMode"},
+ {0x000F0084, nullptr, "GetStepHistoryAll"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm_u.h
new file mode 100644
index 00000000..82749fa3
--- /dev/null
+++ b/src/core/hle/service/ptm_u.h
@@ -0,0 +1,29 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace PTM_U
+
+// ptm service
+
+namespace PTM_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "ptm:u";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 9eb1726a..bb0f80e9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -6,12 +6,22 @@
#include "common/string_util.h"
#include "core/hle/service/service.h"
-#include "core/hle/service/apt.h"
-#include "core/hle/service/fs.h"
-#include "core/hle/service/gsp.h"
-#include "core/hle/service/hid.h"
-#include "core/hle/service/ndm.h"
+#include "core/hle/service/ac_u.h"
+#include "core/hle/service/apt_u.h"
+#include "core/hle/service/cfg_u.h"
+#include "core/hle/service/dsp_dsp.h"
+#include "core/hle/service/err_f.h"
+#include "core/hle/service/fs_user.h"
+#include "core/hle/service/frd_u.h"
+#include "core/hle/service/gsp_gpu.h"
+#include "core/hle/service/hid_user.h"
+#include "core/hle/service/mic_u.h"
+#include "core/hle/service/ndm_u.h"
+#include "core/hle/service/nwm_uds.h"
+#include "core/hle/service/ptm_u.h"
+#include "core/hle/service/soc_u.h"
#include "core/hle/service/srv.h"
+#include "core/hle/service/ssl_c.h"
namespace Service {
@@ -66,11 +76,21 @@ void Init() {
g_manager = new Manager;
g_manager->AddService(new SRV::Interface);
+ g_manager->AddService(new AC_U::Interface);
g_manager->AddService(new APT_U::Interface);
+ g_manager->AddService(new CFG_U::Interface);
+ g_manager->AddService(new DSP_DSP::Interface);
+ g_manager->AddService(new ERR_F::Interface);
+ g_manager->AddService(new FRD_U::Interface);
g_manager->AddService(new FS_User::Interface);
g_manager->AddService(new GSP_GPU::Interface);
g_manager->AddService(new HID_User::Interface);
+ g_manager->AddService(new MIC_U::Interface);
g_manager->AddService(new NDM_U::Interface);
+ g_manager->AddService(new NWM_UDS::Interface);
+ g_manager->AddService(new PTM_U::Interface);
+ g_manager->AddService(new SOC_U::Interface);
+ g_manager->AddService(new SSL_C::Interface);
NOTICE_LOG(HLE, "initialized OK");
}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index c0e803bd..2f5a866c 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -39,11 +39,11 @@ class Interface : public Kernel::Object {
friend class Manager;
public:
- std::string GetName() const { return GetPortName(); }
- std::string GetTypeName() const { return GetPortName(); }
+ std::string GetName() const override { return GetPortName(); }
+ std::string GetTypeName() const override { return GetPortName(); }
static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; }
- Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; }
+ Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Service; }
typedef void (*Function)(Interface*);
@@ -80,7 +80,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result SyncRequest(bool* wait) {
+ Result SyncRequest(bool* wait) override {
u32* cmd_buff = GetCommandBuffer();
auto itr = m_functions.find(cmd_buff[0]);
@@ -113,7 +113,7 @@ public:
* @param wait Boolean wait set if current thread should wait as a result of sync operation
* @return Result of operation, 0 on success, otherwise error code
*/
- Result WaitSynchronization(bool* wait) {
+ Result WaitSynchronization(bool* wait) override {
// TODO(bunnei): ImplementMe
ERROR_LOG(OSHLE, "unimplemented function");
return 0;
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
new file mode 100644
index 00000000..2f891046
--- /dev/null
+++ b/src/core/hle/service/soc_u.cpp
@@ -0,0 +1,58 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/soc_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SOC_U
+
+namespace SOC_U {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010044, nullptr, "InitializeSockets"},
+ {0x000200C2, nullptr, "socket"},
+ {0x00030082, nullptr, "listen"},
+ {0x00040082, nullptr, "accept"},
+ {0x00050084, nullptr, "bind"},
+ {0x00060084, nullptr, "connect"},
+ {0x00070104, nullptr, "recvfrom_other"},
+ {0x00080102, nullptr, "recvfrom"},
+ {0x00090106, nullptr, "sendto_other"},
+ {0x000A0106, nullptr, "sendto"},
+ {0x000B0042, nullptr, "close"},
+ {0x000C0082, nullptr, "shutdown"},
+ {0x000D0082, nullptr, "gethostbyname"},
+ {0x000E00C2, nullptr, "gethostbyaddr"},
+ {0x000F0106, nullptr, "unknown_resolve_ip"},
+ {0x00110102, nullptr, "getsockopt"},
+ {0x00120104, nullptr, "setsockopt"},
+ {0x001300C2, nullptr, "fcntl"},
+ {0x00140084, nullptr, "poll"},
+ {0x00150042, nullptr, "sockatmark"},
+ {0x00160000, nullptr, "gethostid"},
+ {0x00170082, nullptr, "getsockname"},
+ {0x00180082, nullptr, "getpeername"},
+ {0x00190000, nullptr, "ShutdownSockets"},
+ {0x001A00C0, nullptr, "GetNetworkOpt"},
+ {0x001B0040, nullptr, "ICMPSocket"},
+ {0x001C0104, nullptr, "ICMPPing"},
+ {0x001D0040, nullptr, "ICMPCancel"},
+ {0x001E0040, nullptr, "ICMPClose"},
+ {0x001F0040, nullptr, "GetResolverInfo"},
+ {0x00210002, nullptr, "CloseSockets"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
new file mode 100644
index 00000000..e27a2b1f
--- /dev/null
+++ b/src/core/hle/service/soc_u.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SOC_U
+
+namespace SOC_U {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "soc:U";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index eb2c73f9..6c02a43d 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -57,6 +57,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00030100, nullptr, "RegisterService"},
{0x000400C0, nullptr, "UnregisterService"},
{0x00050100, GetServiceHandle, "GetServiceHandle"},
+ {0x000B0000, nullptr, "ReceiveNotification"},
+ {0x000C0080, nullptr, "PublishToSubscriber"}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 9451472d..6d5fe504 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -22,7 +22,7 @@ public:
* Gets the string name used by CTROS for the service
* @return Port name of service
*/
- std::string GetPortName() const {
+ std::string GetPortName() const override {
return "srv:";
}
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
new file mode 100644
index 00000000..4aa660ec
--- /dev/null
+++ b/src/core/hle/service/ssl_c.cpp
@@ -0,0 +1,31 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include "common/log.h"
+#include "core/hle/hle.h"
+#include "core/hle/service/ssl_c.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SSL_C
+
+namespace SSL_C {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000200C2, nullptr, "CreateContext"},
+ {0x00050082, nullptr, "AddTrustedRootCA"},
+ {0x00150082, nullptr, "Read"},
+ {0x00170082, nullptr, "Write"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable, ARRAY_SIZE(FunctionTable));
+}
+
+Interface::~Interface() {
+}
+
+} // namespace
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h
new file mode 100644
index 00000000..7b4e7fd8
--- /dev/null
+++ b/src/core/hle/service/ssl_c.h
@@ -0,0 +1,27 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SSL_C
+
+namespace SSL_C {
+
+class Interface : public Service::Interface {
+public:
+ Interface();
+ ~Interface();
+ /**
+ * Gets the string port name used by CTROS for the service
+ * @return Port name of service
+ */
+ std::string GetPortName() const {
+ return "ssl:C";
+ }
+};
+
+} // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 490e05cd..1eda36c5 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -115,7 +115,7 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
- DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName().c_str(),
+ DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(),
object->GetName().c_str(), nano_seconds);
_assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
@@ -138,7 +138,7 @@ Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wa
bool unlock_all = true;
bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
- DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d",
+ DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld",
handle_count, (wait_all ? "true" : "false"), nano_seconds);
// Iterate through each handle, synchronize kernel object
@@ -324,7 +324,7 @@ Result ClearEvent(Handle evt) {
/// Sleep the current thread
void SleepThread(s64 nanoseconds) {
- DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds);
+ DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds);
}
/// This returns the total CPU ticks elapsed since the CPU was powered-on
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 33a0e0fe..3ad801c6 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -4,11 +4,12 @@
#include "common/common_types.h"
+#include "core/settings.h"
#include "core/core.h"
#include "core/mem_map.h"
#include "core/hle/hle.h"
-#include "core/hle/service/gsp.h"
+#include "core/hle/service/gsp_gpu.h"
#include "core/hw/gpu.h"
@@ -24,6 +25,9 @@ u32 g_cur_line = 0; ///< Current vertical screen line
u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame
+static u32 kFrameCycles = 0; ///< 268MHz / 60 frames per second
+static u32 kFrameTicks = 0; ///< Approximate number of instructions/frame
+
template <typename T>
inline void Read(T &var, const u32 raw_addr) {
u32 addr = raw_addr - 0x1EF00000;
@@ -31,7 +35,7 @@ inline void Read(T &var, const u32 raw_addr) {
// Reads other than u32 are untested, so I'd rather have them abort than silently fail
if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) {
- ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
+ ERROR_LOG(GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
return;
}
@@ -45,7 +49,7 @@ inline void Write(u32 addr, const T data) {
// Writes other than u32 are untested, so I'd rather have them abort than silently fail
if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) {
- ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
+ ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
return;
}
@@ -214,6 +218,9 @@ void Update() {
/// Initialize hardware
void Init() {
+ kFrameCycles = 268123480 / Settings::values.gpu_refresh_rate;
+ kFrameTicks = kFrameCycles / 3;
+
g_cur_line = 0;
g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks();
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 92097d18..3fa7b9cc 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -11,9 +11,6 @@
namespace GPU {
-static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second
-static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame
-
// Returns index corresponding to the Regs member labeled by field_name
// TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
// when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])).
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index efd94f14..33f75c50 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -50,7 +50,7 @@ inline void Read(T &var, const u32 addr) {
break;
default:
- ERROR_LOG(HW, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
+ ERROR_LOG(HW, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
}
}
@@ -68,7 +68,7 @@ inline void Write(u32 addr, const T data) {
break;
default:
- ERROR_LOG(HW, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
+ ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
}
}
diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp
index 158241fd..e29a773f 100644
--- a/src/core/hw/ndma.cpp
+++ b/src/core/hw/ndma.cpp
@@ -10,12 +10,12 @@ namespace NDMA {
template <typename T>
inline void Read(T &var, const u32 addr) {
- ERROR_LOG(NDMA, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr);
+ ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
}
template <typename T>
inline void Write(u32 addr, const T data) {
- ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
+ ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
}
// Explicitly instantiate template functions because we aren't defining this in the header:
diff --git a/src/core/settings.h b/src/core/settings.h
index 77b2f02f..7e7a66b8 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -7,6 +7,7 @@
namespace Settings {
struct Values {
+ // Controls
int pad_a_key;
int pad_b_key;
int pad_x_key;
@@ -25,6 +26,11 @@ struct Values {
int pad_sleft_key;
int pad_sright_key;
+ // Core
+ int cpu_core;
+ int gpu_refresh_rate;
+
+ // Data Storage
bool use_virtual_sd;
bool enable_log;
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index 2cf166af..fbe4047c 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -158,11 +158,11 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
InitScreenCoordinates(vtx2);
DEBUG_LOG(GPU,
- "Triangle %u/%u (%u buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), "
+ "Triangle %lu/%lu (%lu buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), "
"(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
"screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)",
i,output_list.size(), buffer_vertices.size(),
- vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),output_list.size(),
+ vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),
vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(),
vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(),
vtx0.screenpos.x.ToFloat32(), vtx0.screenpos.y.ToFloat32(), vtx0.screenpos.z.ToFloat32(),
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index a9510fa2..1ec72769 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -102,7 +102,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
(vertex_attribute_formats[i] == 2) ? *(s16*)srcdata :
*(float*)srcdata;
input.attr[i][comp] = float24::FromFloat32(srcval);
- DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08x + 0x%04x: %f",
+ DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
comp, i, vertex, index,
attribute_config.GetBaseAddress(),
vertex_attribute_sources[i] - base_address,
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h
index 5a81fcfc..1242eb58 100644
--- a/src/video_core/gpu_debugger.h
+++ b/src/video_core/gpu_debugger.h
@@ -10,7 +10,7 @@
#include "common/log.h"
-#include "core/hle/service/gsp.h"
+#include "core/hle/service/gsp_gpu.h"
#include "command_processor.h"
#include "pica.h"
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 82ef4b14..eed201a9 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -21,19 +21,19 @@ public:
~RendererOpenGL() override;
/// Swap buffers (render frame)
- void SwapBuffers();
+ void SwapBuffers() override;
/**
* Set the emulator window to use for renderer
* @param window EmuWindow handle to emulator window to use for rendering
*/
- void SetWindow(EmuWindow* window);
+ void SetWindow(EmuWindow* window) override;
/// Initialize the renderer
- void Init();
+ void Init() override;
/// Shutdown the renderer
- void ShutDown();
+ void ShutDown() override;
private:
/// Structure used for storing information about the textures for each 3DS screen