diff options
204 files changed, 18674 insertions, 13068 deletions
diff --git a/.gitignore b/.gitignore index cc8abe9ff..659736ff5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Build directory build/ +doc-build/ # Generated source files src/common/scm_rev.cpp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..d7201387a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "externals/inih/inih"] + path = externals/inih/inih + url = https://github.com/svn2github/inih diff --git a/CMakeLists.txt b/CMakeLists.txt index 83b0863f9..bbe9f76cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,7 +68,7 @@ if (ENABLE_GLFW) if (NOT APPLE) find_package(X11 REQUIRED) endif() - + find_package(PkgConfig REQUIRED) pkg_search_module(GLFW REQUIRED glfw3) endif() @@ -127,6 +127,10 @@ get_git_head_revision(GIT_REF_SPEC GIT_REV) git_describe(GIT_DESC --always --long --dirty) git_branch_name(GIT_BRANCH) +set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih") +include_directories(${INI_PREFIX}) +add_subdirectory(${INI_PREFIX}) + # process subdirectories if(ENABLE_QT) include_directories(externals/qhexedit) diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 000000000..981121d92 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,2369 @@ +# Doxyfile 1.8.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Citra + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Nintendo 3DS emulator/debugger" + +# With the PROJECT_LOGO tag one can specify an logo or icon that is included in +# the documentation. The maximum height of the logo should not exceed 55 pixels +# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo +# to the output directory. + +PROJECT_LOGO = doc-icon.png + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc-build/ + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a +# new page for each member. If set to NO, the documentation of a member will be +# part of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by by putting a % sign in front of the word +# or globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = YES + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO these classes will be included in the various overviews. This option has +# no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the +# todo list. This list is created by putting \todo commands in the +# documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the +# test list. This list is created by putting \test commands in the +# documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if <section_label> ... \endif and \cond <section_label> +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES the list +# will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = YES + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = NO + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO doxygen will only warn about wrong or incomplete parameter +# documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = src/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# <filter> <input-file> +# +# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER ) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES, then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefor more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra stylesheet files is of importance (e.g. the last +# stylesheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the stylesheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler ( hhc.exe). If non-empty +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated ( +# YES) or that it should be included in the master .chm file ( NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated ( +# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using prerendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use <access key> + S +# (what the <access key> is depends on the OS and browser, but it is typically +# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down +# key> to jump into the search results window, the results can be navigated +# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel +# the search. The filter options can be selected when the cursor is inside the +# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> +# to select a filter and <Enter> or <escape> to activate or cancel the filter +# option. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a web server instead of a web client using Javascript. There +# are two flavors of web server based searching depending on the EXTERNAL_SEARCH +# setting. When disabled, doxygen will generate a PHP script for searching and +# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing +# and searching needs to be provided by external tools. See the section +# "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SERVER_BASED_SEARCH = NO + +# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP +# script for searching. Instead the search results are written to an XML file +# which needs to be processed by an external indexer. Doxygen will invoke an +# external search engine pointed to by the SEARCHENGINE_URL option to obtain the +# search results. +# +# Doxygen ships with an example indexer ( doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). +# +# See the section "External Indexing and Searching" for details. +# The default value is: NO. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH = NO + +# The SEARCHENGINE_URL should point to a search engine hosted by a web server +# which will return the search results when EXTERNAL_SEARCH is enabled. +# +# Doxygen ships with an example indexer ( doxyindexer) and search engine +# (doxysearch.cgi) which are based on the open source search engine library +# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Searching" for details. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHENGINE_URL = + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed +# search data is written to a file for indexing by an external tool. With the +# SEARCHDATA_FILE tag the name of this file can be specified. +# The default file is: searchdata.xml. +# This tag requires that the tag SEARCHENGINE is set to YES. + +SEARCHDATA_FILE = searchdata.xml + +# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the +# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is +# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple +# projects and redirect the results back to the right project. +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTERNAL_SEARCH_ID = + +# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen +# projects other than the one defined by this configuration file, but that are +# all added to the same external search index. Each project needs to have a +# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of +# to a relative location where the documentation can be found. The format is: +# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... +# This tag requires that the tag SEARCHENGINE is set to YES. + +EXTRA_SEARCH_MAPPINGS = + +#--------------------------------------------------------------------------- +# Configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. +# The default value is: YES. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. +# +# Note that when enabling USE_PDFLATEX this option is only used for generating +# bitmaps for formulas in the HTML output, but not in the Makefile that is +# written to the output directory. +# The default file is: latex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate +# index for LaTeX. +# The default file is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used by the +# printer. +# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x +# 14 inches) and executive (7.25 x 10.5 inches). +# The default value is: a4. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names +# that should be included in the LaTeX output. To get the times font for +# instance you can specify +# EXTRA_PACKAGES=times +# If left blank no extra packages will be included. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the +# generated LaTeX document. The header should contain everything until the first +# chapter. If it is left blank doxygen will generate a standard header. See +# section "Doxygen usage" for information on how to let doxygen write the +# default header to a separate file. +# +# Note: Only use a user-defined header if you know what you are doing! The +# following commands have a special meaning inside the header: $title, +# $datetime, $date, $doxygenversion, $projectname, $projectnumber, +# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string, +# for the replacement values of the other commands the user is refered to +# HTML_HEADER. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the +# generated LaTeX document. The footer should contain everything after the last +# chapter. If it is left blank doxygen will generate a standard footer. See +# LATEX_HEADER for more information on how to generate a default footer and what +# special commands can be used inside the footer. +# +# Note: Only use a user-defined footer if you know what you are doing! +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_FOOTER = + +# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the LATEX_OUTPUT output +# directory. Note that the files will be copied as-is; there are no commands or +# markers available. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EXTRA_FILES = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is +# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will +# contain links (just like the HTML output) instead of page references. This +# makes the output suitable for online browsing using a PDF viewer. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate +# the PDF file directly from the LaTeX files. Set this option to YES to get a +# higher quality PDF documentation. +# The default value is: YES. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode +# command to the generated LaTeX files. This will instruct LaTeX to keep running +# if errors occur, instead of asking the user for help. This option is also used +# when generating formulas in HTML. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BATCHMODE = NO + +# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the +# index chapters (such as File Index, Compound Index, etc.) in the output. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_HIDE_INDICES = NO + +# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source +# code with syntax highlighting in the LaTeX output. +# +# Note that which sources are shown also depends on other settings such as +# SOURCE_BROWSER. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. See +# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# The default value is: plain. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# Configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The +# RTF output is optimized for Word 97 and may not look too pretty with other RTF +# readers/editors. +# The default value is: NO. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: rtf. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF +# documents. This may be useful for small projects and may help to save some +# trees in general. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will +# contain hyperlink fields. The RTF file will contain links (just like the HTML +# output) instead of page references. This makes the output suitable for online +# browsing using Word or some other Word compatible readers that support those +# fields. +# +# Note: WordPad (write) and others do not support links. +# The default value is: NO. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's config +# file, i.e. a series of assignments. You only have to provide replacements, +# missing definitions are set to their default value. +# +# See also section "Doxygen usage" for information on how to generate the +# default style sheet that doxygen normally uses. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an RTF document. Syntax is +# similar to doxygen's config file. A template extensions file can be generated +# using doxygen -e rtf extensionFile. +# This tag requires that the tag GENERATE_RTF is set to YES. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for +# classes and files. +# The default value is: NO. + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. A directory man3 will be created inside the directory specified by +# MAN_OUTPUT. +# The default directory is: man. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to the generated +# man pages. In case the manual section does not start with a number, the number +# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is +# optional. +# The default value is: .3. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_EXTENSION = .3 + +# The MAN_SUBDIR tag determines the name of the directory created within +# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by +# MAN_EXTENSION with the initial . removed. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_SUBDIR = + +# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it +# will generate one additional man file for each entity documented in the real +# man page(s). These additional files only source the real man page, but without +# them the man command would be unable to find the correct page. +# The default value is: NO. +# This tag requires that the tag GENERATE_MAN is set to YES. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that +# captures the structure of the code including all documentation. +# The default value is: NO. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: xml. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_OUTPUT = xml + +# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program +# listings (including syntax highlighting and cross-referencing information) to +# the XML output. Note that enabling this will significantly increase the size +# of the XML output. +# The default value is: YES. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# Configuration options related to the DOCBOOK output +#--------------------------------------------------------------------------- + +# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files +# that can be used to generate PDF. +# The default value is: NO. + +GENERATE_DOCBOOK = NO + +# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in +# front of it. +# The default directory is: docbook. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_OUTPUT = docbook + +# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the +# program listings (including syntax highlighting and cross-referencing +# information) to the DOCBOOK output. Note that enabling this will significantly +# increase the size of the DOCBOOK output. +# The default value is: NO. +# This tag requires that the tag GENERATE_DOCBOOK is set to YES. + +DOCBOOK_PROGRAMLISTING = NO + +#--------------------------------------------------------------------------- +# Configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen +# Definitions (see http://autogen.sf.net) file that captures the structure of +# the code including all documentation. Note that this feature is still +# experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module +# file that captures the structure of the code including all documentation. +# +# Note that this feature is still experimental and incomplete at the moment. +# The default value is: NO. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary +# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI +# output from the Perl module output. +# The default value is: NO. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely +# formatted so it can be parsed by a human reader. This is useful if you want to +# understand what is going on. On the other hand, if this tag is set to NO the +# size of the Perl module output will be much smaller and Perl will parse it +# just the same. +# The default value is: YES. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file are +# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful +# so different doxyrules.make files included by the same Makefile don't +# overwrite each other's variables. +# This tag requires that the tag GENERATE_PERLMOD is set to YES. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all +# C-preprocessor directives found in the sources and include files. +# The default value is: YES. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names +# in the source code. If set to NO only conditional compilation will be +# performed. Macro expansion can be done in a controlled way by setting +# EXPAND_ONLY_PREDEF to YES. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then +# the macro expansion is limited to the macros specified with the PREDEFINED and +# EXPAND_AS_DEFINED tags. +# The default value is: NO. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES the includes files in the +# INCLUDE_PATH will be searched if a #include is found. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by the +# preprocessor. +# This tag requires that the tag SEARCH_INCLUDES is set to YES. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will be +# used. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that are +# defined before the preprocessor is started (similar to the -D option of e.g. +# gcc). The argument of the tag is a list of macros of the form: name or +# name=definition (no spaces). If the definition and the "=" are omitted, "=1" +# is assumed. To prevent a macro definition from being undefined via #undef or +# recursively expanded use the := operator instead of the = operator. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this +# tag can be used to specify a list of macro names that should be expanded. The +# macro definition that is found in the sources will be used. Use the PREDEFINED +# tag if you want to use a different macro definition that overrules the +# definition found in the source code. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will +# remove all references to function-like macros that are alone on a line, have +# an all uppercase name, and do not end with a semicolon. Such function macros +# are typically used for boiler-plate code, and will confuse the parser if not +# removed. +# The default value is: YES. +# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration options related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tag files. For each tag +# file the location of the external documentation should be added. The format of +# a tag file without this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where loc1 and loc2 can be relative or absolute paths or URLs. See the +# section "Linking to external documentation" for more information about the use +# of tag files. +# Note: Each tag file must have a unique name (where the name does NOT include +# the path). If a tag file is not located in the directory in which doxygen is +# run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create a +# tag file that is based on the input files it reads. See section "Linking to +# external documentation" for more information about the usage of tag files. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external class will be listed in the +# class index. If set to NO only the inherited external classes will be listed. +# The default value is: NO. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in +# the modules index. If set to NO, only the current project's groups will be +# listed. +# The default value is: YES. + +EXTERNAL_GROUPS = YES + +# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in +# the related pages index. If set to NO, only the current project's pages will +# be listed. +# The default value is: YES. + +EXTERNAL_PAGES = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of 'which perl'). +# The default file (with absolute path) is: /usr/bin/perl. + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram +# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to +# NO turns the diagrams off. Note that this option also works with HAVE_DOT +# disabled, but it is recommended to install and use dot, since it yields more +# powerful graphs. +# The default value is: YES. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see: +# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. + +DIA_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide inheritance +# and usage relations if the target is undocumented or is not a class. +# The default value is: YES. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz (see: +# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# Bell Labs. The other options in this section have no effect if this option is +# set to NO +# The default value is: NO. + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed +# to run in parallel. When set to 0 doxygen will base this on the number of +# processors available in the system. You can set it explicitly to a value +# larger than 0 to get control over the balance between CPU load and processing +# speed. +# Minimum value: 0, maximum value: 32, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_NUM_THREADS = 0 + +# When you want a differently looking font in the dot files that doxygen +# generates you can specify the font name using DOT_FONTNAME. You need to make +# sure dot is able to find the font, which can be done by putting it in a +# standard location or by setting the DOTFONTPATH environment variable or by +# setting DOT_FONTPATH to the directory containing the font. +# The default value is: Helvetica. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of +# dot graphs. +# Minimum value: 4, maximum value: 24, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the default font as specified with +# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set +# the path where dot can find it using this tag. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_FONTPATH = + +# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for +# each documented class showing the direct and indirect inheritance relations. +# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a +# graph for each documented class showing the direct and indirect implementation +# dependencies (inheritance, containment, and class references variables) of the +# class with other documented classes. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for +# groups, showing the direct groups dependencies. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside the +# class node. If there are many fields or methods and many nodes the graph may +# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the +# number of items for each type to make the size more manageable. Set this to 0 +# for no limit. Note that the threshold may be exceeded by 50% before the limit +# is enforced. So when you set the threshold to 10, up to 15 fields may appear, +# but if the number exceeds 15, the total amount of fields shown is limited to +# 10. +# Minimum value: 0, maximum value: 100, default value: 10. +# This tag requires that the tag HAVE_DOT is set to YES. + +UML_LIMIT_NUM_FIELDS = 10 + +# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and +# collaboration graphs will show the relations between templates and their +# instances. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +TEMPLATE_RELATIONS = NO + +# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to +# YES then doxygen will generate a graph for each documented file showing the +# direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDE_GRAPH = YES + +# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are +# set to YES then doxygen will generate a graph for each documented file showing +# the direct and indirect include dependencies of the file with other documented +# files. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH tag is set to YES then doxygen will generate a call +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller +# dependency graph for every global function or class method. +# +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable caller graphs for selected +# functions only using the \callergraph command. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical +# hierarchy of all classes instead of a textual one. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the +# dependencies a directory has on other directories in a graphical way. The +# dependency relations are determined by the #include relations between the +# files in the directories. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. +# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order +# to make the SVG files visible in IE 9+ (other browsers do not have this +# requirement). +# Possible values are: png, jpg, gif and svg. +# The default value is: png. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# +# Note that this requires a modern browser other than Internet Explorer. Tested +# and working are Firefox, Chrome, Safari, and Opera. +# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make +# the SVG files visible. Older versions of IE do not have SVG support. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +INTERACTIVE_SVG = NO + +# The DOT_PATH tag can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the \dotfile +# command). +# This tag requires that the tag HAVE_DOT is set to YES. + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = + +# The DIAFILE_DIRS tag can be used to specify one or more directories that +# contain dia files that are included in the documentation (see the \diafile +# command). + +DIAFILE_DIRS = + +# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the +# path where java can find the plantuml.jar file. If left blank, it is assumed +# PlantUML is not used or called during a preprocessing step. Doxygen will +# generate a warning when it encounters a \startuml command in this case and +# will not generate output for the diagram. +# This tag requires that the tag HAVE_DOT is set to YES. + +PLANTUML_JAR_PATH = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes +# that will be shown in the graph. If the number of nodes in a graph becomes +# larger than this value, doxygen will truncate the graph, which is visualized +# by representing a node as a red box. Note that doxygen if the number of direct +# children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that +# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. +# Minimum value: 0, maximum value: 10000, default value: 50. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs +# generated by dot. A depth value of 3 means that only nodes reachable from the +# root by following a path via at most 3 edges will be shown. Nodes that lay +# further from the root node will be omitted. Note that setting this option to 1 +# or 2 may greatly reduce the computation time needed for large code bases. Also +# note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. +# Minimum value: 0, maximum value: 1000, default value: 0. +# This tag requires that the tag HAVE_DOT is set to YES. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not seem +# to support this out of the box. +# +# Warning: Depending on the platform used, enabling this option may lead to +# badly anti-aliased labels on the edges of a graph (i.e. they become hard to +# read). +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) support +# this, this feature is disabled by default. +# The default value is: NO. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page +# explaining the meaning of the various boxes and arrows in the dot generated +# graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot +# files that are used to generate the various graphs. +# The default value is: YES. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_CLEANUP = YES diff --git a/doc-icon.png b/doc-icon.png Binary files differnew file mode 100644 index 000000000..420b1546f --- /dev/null +++ b/doc-icon.png diff --git a/externals/inih/CMakeLists.txt b/externals/inih/CMakeLists.txt new file mode 100644 index 000000000..c87f78bfc --- /dev/null +++ b/externals/inih/CMakeLists.txt @@ -0,0 +1,11 @@ +set(SRCS + inih/ini.c + inih/cpp/INIReader.cpp + ) +set(HEADERS + inih/ini.h + inih/cpp/INIReader.h + ) + +create_directory_groups(${SRCS} ${HEADERS}) +add_library(inih ${SRCS} ${HEADERS}) diff --git a/externals/inih/inih b/externals/inih/inih new file mode 160000 +Subproject 603729dec89aaca42d7bd08f08bc333165b7d5d diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt index f10f3e603..f2add394f 100644 --- a/src/citra/CMakeLists.txt +++ b/src/citra/CMakeLists.txt @@ -1,9 +1,12 @@ set(SRCS emu_window/emu_window_glfw.cpp citra.cpp + config.cpp ) set(HEADERS emu_window/emu_window_glfw.h + config.h + default_ini.h resource.h ) @@ -16,7 +19,7 @@ endif() add_executable(citra ${SRCS} ${HEADERS}) target_link_libraries(citra core common video_core) -target_link_libraries(citra ${OPENGL_gl_LIBRARY} ${GLFW_LIBRARIES}) +target_link_libraries(citra ${OPENGL_gl_LIBRARY} ${GLFW_LIBRARIES} inih) if (APPLE) target_link_libraries(citra iconv pthread ${COREFOUNDATION_LIBRARY}) diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 7dc721dc3..6ac5c5dc5 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -4,12 +4,12 @@ #include "common/common.h" #include "common/log_manager.h" -#include "common/file_util.h" #include "core/system.h" #include "core/core.h" #include "core/loader/loader.h" +#include "citra/config.h" #include "citra/emu_window/emu_window_glfw.h" /// Application entry point @@ -21,17 +21,20 @@ int __cdecl main(int argc, char **argv) { return -1; } + Config config; + std::string boot_filename = argv[1]; EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; System::Init(emu_window); - if (Loader::ResultStatus::Success != Loader::LoadFile(boot_filename)) { - ERROR_LOG(BOOT, "Failed to load ROM!"); + Loader::ResultStatus load_result = Loader::LoadFile(boot_filename); + if (Loader::ResultStatus::Success != load_result) { + ERROR_LOG(BOOT, "Failed to load ROM (Error %i)!", load_result); return -1; } - while(true) { + while (emu_window->IsOpen()) { Core::RunLoop(); } diff --git a/src/citra/config.cpp b/src/citra/config.cpp new file mode 100644 index 000000000..c5ce8a164 --- /dev/null +++ b/src/citra/config.cpp @@ -0,0 +1,77 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <GLFW/glfw3.h> + +#include "citra/default_ini.h" +#include "common/file_util.h" +#include "core/settings.h" +#include "core/core.h" + +#include "config.h" + +Config::Config() { + // TODO: Don't hardcode the path; let the frontend decide where to put the config files. + glfw_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "glfw-config.ini"; + glfw_config = new INIReader(glfw_config_loc); + + Reload(); +} + +bool Config::LoadINI(INIReader* config, const char* location, const std::string& default_contents, bool retry) { + if (config->ParseError() < 0) { + if (retry) { + ERROR_LOG(CONFIG, "Failed to load %s. Creating file from defaults...", location); + FileUtil::CreateFullPath(location); + FileUtil::WriteStringToFile(true, default_contents, location); + *config = INIReader(location); // Reopen file + + return LoadINI(config, location, default_contents, false); + } + ERROR_LOG(CONFIG, "Failed."); + return false; + } + INFO_LOG(CONFIG, "Successfully loaded %s", location); + return true; +} + +void Config::ReadControls() { + Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A); + Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S); + Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z); + Settings::values.pad_y_key = glfw_config->GetInteger("Controls", "pad_y", GLFW_KEY_X); + Settings::values.pad_l_key = glfw_config->GetInteger("Controls", "pad_l", GLFW_KEY_Q); + Settings::values.pad_r_key = glfw_config->GetInteger("Controls", "pad_r", GLFW_KEY_W); + Settings::values.pad_start_key = glfw_config->GetInteger("Controls", "pad_start", GLFW_KEY_M); + Settings::values.pad_select_key = glfw_config->GetInteger("Controls", "pad_select", GLFW_KEY_N); + Settings::values.pad_home_key = glfw_config->GetInteger("Controls", "pad_home", GLFW_KEY_B); + Settings::values.pad_dup_key = glfw_config->GetInteger("Controls", "pad_dup", GLFW_KEY_T); + Settings::values.pad_ddown_key = glfw_config->GetInteger("Controls", "pad_ddown", GLFW_KEY_G); + Settings::values.pad_dleft_key = glfw_config->GetInteger("Controls", "pad_dleft", GLFW_KEY_F); + Settings::values.pad_dright_key = glfw_config->GetInteger("Controls", "pad_dright", GLFW_KEY_H); + Settings::values.pad_sup_key = glfw_config->GetInteger("Controls", "pad_sup", GLFW_KEY_UP); + Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN); + Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT); + Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT); +} + +void Config::ReadCore() { + Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter); + Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 60); +} + +void Config::ReadData() { + Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true); +} + +void Config::Reload() { + LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file); + ReadControls(); + ReadCore(); + ReadData(); +} + +Config::~Config() { + delete glfw_config; +} diff --git a/src/citra/config.h b/src/citra/config.h new file mode 100644 index 000000000..4f6551876 --- /dev/null +++ b/src/citra/config.h @@ -0,0 +1,26 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <map> + +#include <inih/cpp/INIReader.h> + +#include "common/common_types.h" + +class Config { + INIReader* glfw_config; + std::string glfw_config_loc; + + bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true); + void ReadControls(); + void ReadCore(); + void ReadData(); +public: + Config(); + ~Config(); + + void Reload(); +}; diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h new file mode 100644 index 000000000..557da881b --- /dev/null +++ b/src/citra/default_ini.h @@ -0,0 +1,37 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +namespace DefaultINI { + +const char* glfw_config_file = R"( +[Controls] +pad_start = +pad_select = +pad_home = +pad_dup = +pad_ddown = +pad_dleft = +pad_dright = +pad_a = +pad_b = +pad_x = +pad_y = +pad_r = +pad_l = +pad_sup = +pad_sdown = +pad_sleft = +pad_sright = + +[Core] +cpu_core = ## 0: Interpreter (default), 1: FastInterpreter (experimental) +gpu_refresh_rate = ## 60 (default) + +[Data Storage] +use_virtual_sd = +)"; + +} diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp index 02f524e03..0c774bbc5 100644 --- a/src/citra/emu_window/emu_window_glfw.cpp +++ b/src/citra/emu_window/emu_window_glfw.cpp @@ -6,20 +6,40 @@ #include "video_core/video_core.h" +#include "core/settings.h" + #include "citra/emu_window/emu_window_glfw.h" -static void OnKeyEvent(GLFWwindow* win, int key, int action) { - // TODO(bunnei): ImplementMe +/// Called by GLFW when a key event occurs +void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) { + + if (!VideoCore::g_emu_window) { + return; + } + + int keyboard_id = ((EmuWindow_GLFW*)VideoCore::g_emu_window)->keyboard_id; + + if (action == GLFW_PRESS) { + EmuWindow::KeyPressed({key, keyboard_id}); + } + + if (action == GLFW_RELEASE) { + EmuWindow::KeyReleased({key, keyboard_id}); + } + HID_User::PadUpdateComplete(); } -static void OnWindowSizeEvent(GLFWwindow* win, int width, int height) { - EmuWindow_GLFW* emu_window = (EmuWindow_GLFW*)glfwGetWindowUserPointer(win); - emu_window->SetClientAreaWidth(width); - emu_window->SetClientAreaHeight(height); +/// Whether the window is still open, and a close request hasn't yet been sent +const bool EmuWindow_GLFW::IsOpen() { + return glfwWindowShouldClose(m_render_window) == 0; } /// EmuWindow_GLFW constructor EmuWindow_GLFW::EmuWindow_GLFW() { + keyboard_id = KeyMap::NewDeviceId(); + + ReloadSetKeymaps(); + // Initialize the window if(glfwInit() != GL_TRUE) { printf("Failed to initialize GLFW! Exiting..."); @@ -27,12 +47,9 @@ EmuWindow_GLFW::EmuWindow_GLFW() { } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); - -#if EMU_PLATFORM == PLATFORM_MACOSX // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context. glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); -#endif m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), @@ -45,8 +62,7 @@ EmuWindow_GLFW::EmuWindow_GLFW() { // Setup callbacks glfwSetWindowUserPointer(m_render_window, this); - //glfwSetKeyCallback(m_render_window, OnKeyEvent); - //glfwSetWindowSizeCallback(m_render_window, OnWindowSizeEvent); + glfwSetKeyCallback(m_render_window, OnKeyEvent); DoneCurrent(); } @@ -75,3 +91,22 @@ void EmuWindow_GLFW::MakeCurrent() { void EmuWindow_GLFW::DoneCurrent() { glfwMakeContextCurrent(NULL); } + +void EmuWindow_GLFW::ReloadSetKeymaps() { + KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A); + KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B); + KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT); + KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START); + KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT); + KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT); + KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP); + KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN); + KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R); + KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L); + KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X); + KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y); + KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT); + KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT); + KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP); + KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); +} diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h index c1b41203b..7c3072145 100644 --- a/src/citra/emu_window/emu_window_glfw.h +++ b/src/citra/emu_window/emu_window_glfw.h @@ -14,19 +14,27 @@ public: ~EmuWindow_GLFW(); /// Swap buffers to display the next frame - void SwapBuffers(); + void SwapBuffers() override; /// Polls window events - void PollEvents(); + void PollEvents() override; /// Makes the graphics context current for the caller thread - void MakeCurrent(); + void MakeCurrent() override; /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread - void DoneCurrent(); + void DoneCurrent() override; - GLFWwindow* m_render_window; ///< Internal GLFW render window + static void OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods); + + /// Whether the window is still open, and a close request hasn't yet been sent + const bool IsOpen(); + + void ReloadSetKeymaps() override; private: + GLFWwindow* m_render_window; ///< Internal GLFW render window + /// Device id of keyboard for use with KeyMap + int keyboard_id; }; diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 426e4ef99..98a48a69a 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -4,6 +4,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(SRCS config/controller_config.cpp config/controller_config_util.cpp + config.cpp debugger/callstack.cpp debugger/disassembler.cpp debugger/graphics.cpp @@ -18,6 +19,7 @@ set(SRCS set(HEADERS config/controller_config.hxx config/controller_config_util.hxx + config.h debugger/callstack.hxx debugger/disassembler.hxx debugger/graphics.hxx diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 573060d30..20824692d 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -6,12 +6,11 @@ #include "bootmanager.hxx" #include "core/core.h" -#include "core/loader/loader.h" -#include "core/hw/hw.h" +#include "core/settings.h" #include "video_core/video_core.h" -#include "version.h" +#include "citra_qt/version.h" #define APP_NAME "citra" #define APP_VERSION "0.1-" VERSION @@ -19,9 +18,8 @@ #define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" EmuThread::EmuThread(GRenderWindow* render_window) : - exec_cpu_step(false), cpu_running(false), - render_window(render_window), filename(""), - stop_run(false) + filename(""), exec_cpu_step(false), cpu_running(false), + stop_run(false), render_window(render_window) { } @@ -35,19 +33,16 @@ void EmuThread::run() stop_run = false; while (!stop_run) { - for (int tight_loop = 0; tight_loop < 10000; ++tight_loop) + if (cpu_running) { - if (cpu_running || exec_cpu_step) - { - if (exec_cpu_step) - exec_cpu_step = false; - - Core::SingleStep(); - if (!cpu_running) { - emit CPUStepped(); - yieldCurrentThread(); - } - } + Core::RunLoop(); + } + else if (exec_cpu_step) + { + exec_cpu_step = false; + Core::SingleStep(); + emit CPUStepped(); + yieldCurrentThread(); } } render_window->moveContext(); @@ -92,10 +87,10 @@ public: parent_ = parent; } - void paintEvent(QPaintEvent* ev) + void paintEvent(QPaintEvent* ev) override { } - void resizeEvent(QResizeEvent* ev) { + void resizeEvent(QResizeEvent* ev) override { parent_->SetClientAreaWidth(size().width()); parent_->SetClientAreaHeight(size().height()); } @@ -103,20 +98,22 @@ private: GRenderWindow* parent_; }; - EmuThread& GRenderWindow::GetEmuThread() { return emu_thread; } -GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this) +GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0) { + keyboard_id = KeyMap::NewDeviceId(); + ReloadSetKeymaps(); + // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, WA_DontShowOnScreen, WA_DeleteOnClose QGLFormat fmt; - fmt.setProfile(QGLFormat::CoreProfile); fmt.setVersion(3,2); - fmt.setSampleBuffers(true); - fmt.setSamples(4); + fmt.setProfile(QGLFormat::CoreProfile); + // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X + fmt.setOption(QGL::NoDeprecatedFunctions); child = new GGLWidgetInternal(fmt, this); QBoxLayout* layout = new QHBoxLayout(this); @@ -209,27 +206,33 @@ QByteArray GRenderWindow::saveGeometry() void GRenderWindow::keyPressEvent(QKeyEvent* event) { - /* - bool key_processed = false; - for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) - if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::PRESSED)) - key_processed = true; - - if (!key_processed) - QWidget::keyPressEvent(event); - */ + EmuWindow::KeyPressed({event->key(), keyboard_id}); + HID_User::PadUpdateComplete(); } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { - /* - bool key_processed = false; - for (unsigned int channel = 0; channel < 4 && controller_interface(); ++channel) - if (controller_interface()->SetControllerStatus(channel, event->key(), input_common::GCController::RELEASED)) - key_processed = true; - - if (!key_processed) - QWidget::keyPressEvent(event); - */ + EmuWindow::KeyReleased({event->key(), keyboard_id}); + HID_User::PadUpdateComplete(); +} + +void GRenderWindow::ReloadSetKeymaps() +{ + KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A); + KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B); + KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT); + KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START); + KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT); + KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT); + KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP); + KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN); + KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R); + KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L); + KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X); + KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y); + KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT); + KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT); + KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP); + KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); } diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx index 51cb781e9..f8afc403e 100644 --- a/src/citra_qt/bootmanager.hxx +++ b/src/citra_qt/bootmanager.hxx @@ -25,7 +25,7 @@ public: * * @warning Only call when not running! */ - void run(); + void run() override; /** * Allow the CPU to process a single instruction (if cpu is not running) @@ -89,13 +89,13 @@ public: GRenderWindow(QWidget* parent = NULL); ~GRenderWindow(); - void closeEvent(QCloseEvent*); + void closeEvent(QCloseEvent*) override; // EmuWindow implementation - void SwapBuffers(); - void MakeCurrent(); - void DoneCurrent(); - void PollEvents(); + void SwapBuffers() override; + void MakeCurrent() override; + void DoneCurrent() override; + void PollEvents() override; void BackupGeometry(); void RestoreGeometry(); @@ -104,8 +104,10 @@ public: EmuThread& GetEmuThread(); - void keyPressEvent(QKeyEvent* event); - void keyReleaseEvent(QKeyEvent* event); + void keyPressEvent(QKeyEvent* event) override; + void keyReleaseEvent(QKeyEvent* event) override; + + void ReloadSetKeymaps() override; public slots: void moveContext(); @@ -116,4 +118,7 @@ private: EmuThread emu_thread; QByteArray geometry; + + /// Device id of keyboard for use with KeyMap + int keyboard_id; }; diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp new file mode 100644 index 000000000..63d396439 --- /dev/null +++ b/src/citra_qt/config.cpp @@ -0,0 +1,110 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <QString> +#include <QStringList> + +#include "core/settings.h" +#include "core/core.h" +#include "common/file_util.h" + +#include "config.h" + +Config::Config() { + + // TODO: Don't hardcode the path; let the frontend decide where to put the config files. + qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini"; + FileUtil::CreateFullPath(qt_config_loc); + qt_config = new QSettings(QString::fromStdString(qt_config_loc), QSettings::IniFormat); + + Reload(); +} + +void Config::ReadControls() { + qt_config->beginGroup("Controls"); + Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt(); + Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt(); + Settings::values.pad_x_key = qt_config->value("pad_x", Qt::Key_Z).toInt(); + Settings::values.pad_y_key = qt_config->value("pad_y", Qt::Key_X).toInt(); + Settings::values.pad_l_key = qt_config->value("pad_l", Qt::Key_Q).toInt(); + Settings::values.pad_r_key = qt_config->value("pad_r", Qt::Key_W).toInt(); + Settings::values.pad_start_key = qt_config->value("pad_start", Qt::Key_M).toInt(); + Settings::values.pad_select_key = qt_config->value("pad_select", Qt::Key_N).toInt(); + Settings::values.pad_home_key = qt_config->value("pad_home", Qt::Key_B).toInt(); + Settings::values.pad_dup_key = qt_config->value("pad_dup", Qt::Key_T).toInt(); + Settings::values.pad_ddown_key = qt_config->value("pad_ddown", Qt::Key_G).toInt(); + Settings::values.pad_dleft_key = qt_config->value("pad_dleft", Qt::Key_F).toInt(); + Settings::values.pad_dright_key = qt_config->value("pad_dright", Qt::Key_H).toInt(); + Settings::values.pad_sup_key = qt_config->value("pad_sup", Qt::Key_Up).toInt(); + Settings::values.pad_sdown_key = qt_config->value("pad_sdown", Qt::Key_Down).toInt(); + Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt(); + Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt(); + qt_config->endGroup(); +} + +void Config::SaveControls() { + qt_config->beginGroup("Controls"); + qt_config->setValue("pad_a", Settings::values.pad_a_key); + qt_config->setValue("pad_b", Settings::values.pad_b_key); + qt_config->setValue("pad_x", Settings::values.pad_x_key); + qt_config->setValue("pad_y", Settings::values.pad_y_key); + qt_config->setValue("pad_l", Settings::values.pad_l_key); + qt_config->setValue("pad_r", Settings::values.pad_r_key); + qt_config->setValue("pad_start", Settings::values.pad_start_key); + qt_config->setValue("pad_select", Settings::values.pad_select_key); + qt_config->setValue("pad_home", Settings::values.pad_home_key); + qt_config->setValue("pad_dup", Settings::values.pad_dup_key); + qt_config->setValue("pad_ddown", Settings::values.pad_ddown_key); + qt_config->setValue("pad_dleft", Settings::values.pad_dleft_key); + qt_config->setValue("pad_dright", Settings::values.pad_dright_key); + qt_config->setValue("pad_sup", Settings::values.pad_sup_key); + qt_config->setValue("pad_sdown", Settings::values.pad_sdown_key); + qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key); + qt_config->setValue("pad_sright", Settings::values.pad_sright_key); + qt_config->endGroup(); +} + +void Config::ReadCore() { + qt_config->beginGroup("Core"); + Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt(); + Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 60).toInt(); + qt_config->endGroup(); +} + +void Config::SaveCore() { + qt_config->beginGroup("Core"); + qt_config->setValue("cpu_core", Settings::values.cpu_core); + qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate); + qt_config->endGroup(); +} + +void Config::ReadData() { + qt_config->beginGroup("Data Storage"); + Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool(); + qt_config->endGroup(); +} + +void Config::SaveData() { + qt_config->beginGroup("Data Storage"); + qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); + qt_config->endGroup(); +} + +void Config::Reload() { + ReadControls(); + ReadCore(); + ReadData(); +} + +void Config::Save() { + SaveControls(); + SaveCore(); + SaveData(); +} + +Config::~Config() { + Save(); + + delete qt_config; +} diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h new file mode 100644 index 000000000..782c26287 --- /dev/null +++ b/src/citra_qt/config.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <QSettings> + +#include "common/common_types.h" + +class Config { + QSettings* qt_config; + std::string qt_config_loc; + + void ReadControls(); + void SaveControls(); + void ReadCore(); + void SaveCore(); + void ReadData(); + void SaveData(); +public: + Config(); + ~Config(); + + void Reload(); + void Save(); +}; diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index 856baf63d..2ee877743 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -9,7 +9,7 @@ #include "core/core.h" #include "common/break_points.h" #include "common/symbols.h" -#include "core/arm/interpreter/armdefs.h" +#include "core/arm/skyeye_common/armdefs.h" #include "core/arm/disassembler/arm_disasm.h" DisassemblerModel::DisassemblerModel(QObject* parent) : QAbstractItemModel(parent), base_address(0), code_size(0), program_counter(0), selection(QModelIndex()) { diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx index 479ef0326..1523e724f 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.hxx +++ b/src/citra_qt/debugger/graphics_cmdlists.hxx @@ -17,7 +17,7 @@ class GPUCommandListModel : public QAbstractListModel public: GPUCommandListModel(QObject* parent); - int columnCount(const QModelIndex& parent = QModelIndex()) const; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; int rowCount(const QModelIndex& parent = QModelIndex()) const override; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 1bf9bc53c..304c169b9 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -26,12 +26,16 @@ #include "core/core.h" #include "core/loader/loader.h" #include "core/arm/disassembler/load_symbol_map.h" +#include "citra_qt/config.h" #include "version.h" GMainWindow::GMainWindow() { + LogManager::Init(); + Config config; + ui.setupUi(this); statusBar()->hide(); @@ -112,8 +116,10 @@ GMainWindow::GMainWindow() show(); - LogManager::Init(); - System::Init(render_window); + QStringList args = QApplication::arguments(); + if (args.length() >= 2) { + BootGame(args[1].toStdString()); + } } GMainWindow::~GMainWindow() @@ -125,10 +131,11 @@ GMainWindow::~GMainWindow() void GMainWindow::BootGame(std::string filename) { - NOTICE_LOG(MASTER_LOG, "citra starting...\n"); + NOTICE_LOG(MASTER_LOG, "Citra starting...\n"); + System::Init(render_window); if (Core::Init()) { - ERROR_LOG(MASTER_LOG, "core initialization failed, exiting..."); + ERROR_LOG(MASTER_LOG, "Core initialization failed, exiting..."); Core::Stop(); exit(1); } @@ -146,6 +153,7 @@ void GMainWindow::BootGame(std::string filename) render_window->GetEmuThread().start(); render_window->show(); + OnStartGame(); } void GMainWindow::OnMenuLoadFile() @@ -182,6 +190,7 @@ void GMainWindow::OnPauseGame() void GMainWindow::OnStopGame() { render_window->GetEmuThread().SetCpuRunning(false); + // TODO: Shutdown core ui.action_Start->setEnabled(true); ui.action_Pause->setEnabled(false); @@ -243,7 +252,6 @@ int __cdecl main(int argc, char* argv[]) QApplication::setAttribute(Qt::AA_X11InitThreads); QApplication app(argc, argv); GMainWindow main_window; - main_window.show(); return app.exec(); } diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx index a0b41f5f4..b1b40df46 100644 --- a/src/citra_qt/main.hxx +++ b/src/citra_qt/main.hxx @@ -32,7 +32,7 @@ public: private: void BootGame(std::string filename); - void closeEvent(QCloseEvent* event); + void closeEvent(QCloseEvent* event) override; private slots: void OnStartGame(); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 868fda55e..9d5a90762 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -4,10 +4,12 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU set(SRCS break_points.cpp console_listener.cpp + emu_window.cpp extended_trace.cpp file_search.cpp file_util.cpp hash.cpp + key_map.cpp log_manager.cpp math_util.cpp mem_arena.cpp @@ -38,8 +40,8 @@ set(HEADERS fifo_queue.h file_search.h file_util.h - fixed_size_queue.h hash.h + key_map.h linear_disk_cache.h log.h log_manager.h diff --git a/src/common/bit_field.h b/src/common/bit_field.h index b6f0179c6..9e02210f9 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h @@ -68,7 +68,7 @@ * u32 hex; * * BitField<0,7,u32> first_seven_bits; // unsigned - * BitField<7,8,32> next_eight_bits; // unsigned + * BitField<7,8,u32> next_eight_bits; // unsigned * BitField<3,15,s32> some_signed_fields; // signed * }; * diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h index 2b0f120e6..dc8ac1fd9 100644 --- a/src/common/chunk_file.h +++ b/src/common/chunk_file.h @@ -32,35 +32,10 @@ #include <string> #include <list> #include <set> -#ifndef __SYMBIAN32__ -#if defined(IOS) || defined(MACGNUSTD) -#include <tr1/type_traits> -#else #include <type_traits> -#endif -#endif #include "common/common.h" #include "common/file_util.h" -//#include "../ext/snappy/snappy-c.h" - -#if defined(IOS) || defined(MACGNUSTD) -namespace std { - using tr1::is_pointer; -} -#endif -#ifdef __SYMBIAN32__ -namespace std { - template <bool bool_value> - struct bool_constant { - typedef bool_constant<bool_value> type; - static const bool value = bool_value; - }; - template <bool bool_value> const bool bool_constant<bool_value>::value; - template <typename T> struct is_pointer : public bool_constant<false> {}; - template <typename T> struct is_pointer<T*> : public bool_constant<true> {}; -} -#endif template <class T> struct LinkedListItem : public T @@ -651,222 +626,3 @@ inline PointerWrapSection::~PointerWrapSection() { p_.DoMarker(title_); } } - - -// Commented out because it is currently unused, and breaks builds on OSX -/*class CChunkFileReader -{ -public: - enum Error { - ERROR_NONE, - ERROR_BAD_FILE, - ERROR_BROKEN_STATE, - }; - - // Load file template - template<class T> - static Error Load(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class, std::string* _failureReason) - { - INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str()); - _failureReason->clear(); - _failureReason->append("LoadStateWrongVersion"); - - if (!File::Exists(_rFilename)) { - _failureReason->clear(); - _failureReason->append("LoadStateDoesntExist"); - ERROR_LOG(COMMON, "ChunkReader: File doesn't exist"); - return ERROR_BAD_FILE; - } - - // Check file size - const u64 fileSize = File::GetSize(_rFilename); - static const u64 headerSize = sizeof(SChunkHeader); - if (fileSize < headerSize) - { - ERROR_LOG(COMMON,"ChunkReader: File too small"); - return ERROR_BAD_FILE; - } - - File::IOFile pFile(_rFilename, "rb"); - if (!pFile) - { - ERROR_LOG(COMMON,"ChunkReader: Can't open file for reading"); - return ERROR_BAD_FILE; - } - - // read the header - SChunkHeader header; - if (!pFile.ReadArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Bad header size"); - return ERROR_BAD_FILE; - } - - // Check revision - if (header.Revision != _Revision) - { - ERROR_LOG(COMMON,"ChunkReader: Wrong file revision, got %d expected %d", - header.Revision, _Revision); - return ERROR_BAD_FILE; - } - - if (strcmp(header.GitVersion, _VersionString) != 0) - { - WARN_LOG(COMMON, "This savestate was generated by a different version of PPSSPP, %s. It may not load properly.", - header.GitVersion); - } - - // get size - const int sz = (int)(fileSize - headerSize); - if (header.ExpectedSize != sz) - { - ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d", - sz, header.ExpectedSize); - return ERROR_BAD_FILE; - } - - // read the state - u8* buffer = new u8[sz]; - if (!pFile.ReadBytes(buffer, sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Error reading file"); - return ERROR_BAD_FILE; - } - - u8 *ptr = buffer; - u8 *buf = buffer; - if (header.Compress) { - u8 *uncomp_buffer = new u8[header.UncompressedSize]; - size_t uncomp_size = header.UncompressedSize; - snappy_uncompress((const char *)buffer, sz, (char *)uncomp_buffer, &uncomp_size); - if ((int)uncomp_size != header.UncompressedSize) { - ERROR_LOG(COMMON,"Size mismatch: file: %i calc: %i", (int)header.UncompressedSize, (int)uncomp_size); - } - ptr = uncomp_buffer; - buf = uncomp_buffer; - delete [] buffer; - } - - PointerWrap p(&ptr, PointerWrap::MODE_READ); - _class.DoState(p); - delete[] buf; - - INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - // Save file template - template<class T> - static Error Save(const std::string& _rFilename, int _Revision, const char *_VersionString, T& _class) - { - INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str()); - - File::IOFile pFile(_rFilename, "wb"); - if (!pFile) - { - ERROR_LOG(COMMON,"ChunkReader: Error opening file for write"); - return ERROR_BAD_FILE; - } - - bool compress = true; - - // Get data - u8 *ptr = 0; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - - u8 * buffer = new u8[sz]; - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Create header - SChunkHeader header; - header.Compress = compress ? 1 : 0; - header.Revision = _Revision; - header.ExpectedSize = (int)sz; - header.UncompressedSize = (int)sz; - strncpy(header.GitVersion, _VersionString, 32); - header.GitVersion[31] = '\0'; - - // Write to file - if (compress) { - size_t comp_len = snappy_max_compressed_length(sz); - u8 *compressed_buffer = new u8[comp_len]; - snappy_compress((const char *)buffer, sz, (char *)compressed_buffer, &comp_len); - delete [] buffer; - header.ExpectedSize = (int)comp_len; - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return ERROR_BAD_FILE; - } - if (!pFile.WriteBytes(&compressed_buffer[0], comp_len)) { - ERROR_LOG(COMMON,"ChunkReader: Failed writing compressed data"); - return ERROR_BAD_FILE; - } else { - INFO_LOG(COMMON, "Savestate: Compressed %i bytes into %i", (int)sz, (int)comp_len); - } - delete [] compressed_buffer; - } else { - if (!pFile.WriteArray(&header, 1)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing header"); - return ERROR_BAD_FILE; - } - if (!pFile.WriteBytes(&buffer[0], sz)) - { - ERROR_LOG(COMMON,"ChunkReader: Failed writing data"); - return ERROR_BAD_FILE; - } - delete [] buffer; - } - - INFO_LOG(COMMON,"ChunkReader: Done writing %s", - _rFilename.c_str()); - if (p.error != p.ERROR_FAILURE) { - return ERROR_NONE; - } else { - return ERROR_BROKEN_STATE; - } - } - - template <class T> - static Error Verify(T& _class) - { - u8 *ptr = 0; - - // Step 1: Measure the space required. - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - _class.DoState(p); - size_t const sz = (size_t)ptr; - std::vector<u8> buffer(sz); - - // Step 2: Dump the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_WRITE); - _class.DoState(p); - - // Step 3: Verify the state. - ptr = &buffer[0]; - p.SetMode(PointerWrap::MODE_VERIFY); - _class.DoState(p); - - return ERROR_NONE; - } - -private: - struct SChunkHeader - { - int Revision; - int Compress; - int ExpectedSize; - int UncompressedSize; - char GitVersion[32]; - }; -}; */ diff --git a/src/common/common.h b/src/common/common.h index cb69eabe4..9f3016d34 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -20,11 +20,6 @@ #define STACKALIGN -#if __cplusplus >= 201103L || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__) -#define HAVE_CXX11_SYNTAX 1 -#endif - -#if HAVE_CXX11_SYNTAX // An inheritable class to disallow the copy constructor and operator= functions class NonCopyable { @@ -36,7 +31,6 @@ private: NonCopyable(NonCopyable&); NonCopyable& operator=(NonCopyable& other); }; -#endif #include "common/log.h" #include "common/common_types.h" diff --git a/src/common/common_paths.h b/src/common/common_paths.h index a36de9227..ae08d082a 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h @@ -7,25 +7,25 @@ // Make sure we pick up USER_DIR if set in config.h #include "common/common.h" -// Directory seperators, do we need this? +// Directory separators, do we need this? #define DIR_SEP "/" #define DIR_SEP_CHR '/' #ifndef MAX_PATH -#define MAX_PATH 260 +#define MAX_PATH 260 #endif // The user data dir #define ROOT_DIR "." #ifdef _WIN32 #define USERDATA_DIR "user" - #define EMU_DATA_DIR "emu" + #define EMU_DATA_DIR "Citra Emulator" #else #define USERDATA_DIR "user" #ifdef USER_DIR #define EMU_DATA_DIR USER_DIR #else - #define EMU_DATA_DIR ".emu" + #define EMU_DATA_DIR ".citra-emu" #endif #endif @@ -48,29 +48,30 @@ #define JAP_DIR "JAP" // Subdirs in the User dir returned by GetUserPath(D_USER_IDX) -#define CONFIG_DIR "config" -#define GAMECONFIG_DIR "game_config" -#define MAPS_DIR "maps" -#define CACHE_DIR "cache" -#define SHADERCACHE_DIR "shader_cache" -#define STATESAVES_DIR "state_saves" -#define SCREENSHOTS_DIR "screenShots" -#define DUMP_DIR "dump" -#define DUMP_TEXTURES_DIR "textures" -#define DUMP_FRAMES_DIR "frames" -#define DUMP_AUDIO_DIR "audio" -#define LOGS_DIR "logs" -#define SHADERS_DIR "shaders" -#define SYSCONF_DIR "sysconf" +#define CONFIG_DIR "config" +#define GAMECONFIG_DIR "game_config" +#define MAPS_DIR "maps" +#define CACHE_DIR "cache" +#define SDMC_DIR "sdmc" +#define SHADERCACHE_DIR "shader_cache" +#define STATESAVES_DIR "state_saves" +#define SCREENSHOTS_DIR "screenShots" +#define DUMP_DIR "dump" +#define DUMP_TEXTURES_DIR "textures" +#define DUMP_FRAMES_DIR "frames" +#define DUMP_AUDIO_DIR "audio" +#define LOGS_DIR "logs" +#define SHADERS_DIR "shaders" +#define SYSCONF_DIR "sysconf" // Filenames // Files in the directory returned by GetUserPath(D_CONFIG_IDX) #define EMU_CONFIG "emu.ini" -#define DEBUGGER_CONFIG "debugger.ini" -#define LOGGER_CONFIG "logger.ini" +#define DEBUGGER_CONFIG "debugger.ini" +#define LOGGER_CONFIG "logger.ini" // Files in the directory returned by GetUserPath(D_LOGS_IDX) -#define MAIN_LOG "emu.log" +#define MAIN_LOG "emu.log" // Files in the directory returned by GetUserPath(D_SYSCONF_IDX) -#define SYSCONF "SYSCONF" +#define SYSCONF "SYSCONF" diff --git a/src/common/common_types.h b/src/common/common_types.h index 9d41e5971..7ce6b2240 100644 --- a/src/common/common_types.h +++ b/src/common/common_types.h @@ -25,42 +25,21 @@ #pragma once #include <cmath> +#include <cstdint> #include <xmmintrin.h> // data_types__m128.cpp -#ifdef _WIN32 +typedef std::uint8_t u8; ///< 8-bit unsigned byte +typedef std::uint16_t u16; ///< 16-bit unsigned short +typedef std::uint32_t u32; ///< 32-bit unsigned word +typedef std::uint64_t u64; ///< 64-bit unsigned int -#include <tchar.h> +typedef std::int8_t s8; ///< 8-bit signed byte +typedef std::int16_t s16; ///< 16-bit signed short +typedef std::int32_t s32; ///< 32-bit signed word +typedef std::int64_t s64; ///< 64-bit signed int -typedef unsigned __int8 u8; ///< 8-bit unsigned byte -typedef unsigned __int16 u16; ///< 16-bit unsigned short -typedef unsigned __int32 u32; ///< 32-bit unsigned word -typedef unsigned __int64 u64; ///< 64-bit unsigned int - -typedef signed __int8 s8; ///< 8-bit signed byte -typedef signed __int16 s16; ///< 16-bit signed short -typedef signed __int32 s32; ///< 32-bit signed word -typedef signed __int64 s64; ///< 64-bit signed int - -#else - -typedef unsigned char u8; ///< 8-bit unsigned byte -typedef unsigned short u16; ///< 16-bit unsigned short -typedef unsigned int u32; ///< 32-bit unsigned word -typedef unsigned long long u64; ///< 64-bit unsigned int - -typedef signed char s8; ///< 8-bit signed byte -typedef signed short s16; ///< 16-bit signed short -typedef signed int s32; ///< 32-bit signed word -typedef signed long long s64; ///< 64-bit signed int - -// For using windows lock code -#define TCHAR char -#define LONG int - -#endif // _WIN32 - -typedef float f32; ///< 32-bit floating point -typedef double f64; ///< 64-bit floating point +typedef float f32; ///< 32-bit floating point +typedef double f64; ///< 64-bit floating point #include "common/common.h" @@ -100,7 +79,7 @@ union t128 { __m128 a; ///< 128-bit floating point (__m128 maps to the XMM[0-7] registers) }; -namespace common { +namespace Common { /// Rectangle data structure class Rect { public: diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp index 27697ef1f..53f20d754 100644 --- a/src/common/console_listener.cpp +++ b/src/common/console_listener.cpp @@ -3,14 +3,10 @@ // Refer to the license.txt file included. #include <algorithm> -#include <cmath> -#include <cstdio> -#include <string> + #ifdef _WIN32 #include <windows.h> #include <array> -#else -#include <cstdarg> #endif #include "common/common.h" @@ -47,7 +43,7 @@ void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title // Save the window handle that AllocConsole() created hConsole = GetStdHandle(STD_OUTPUT_HANDLE); // Set the console window title - SetConsoleTitle(UTF8ToTStr(Title).c_str()); + SetConsoleTitle(Common::UTF8ToTStr(Title).c_str()); // Set letter space LetterSpace(80, 4000); //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true); @@ -193,11 +189,11 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool { Str.resize(Str.size() + 1); if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead)) - SLog += StringFromFormat("WriteConsoleOutputCharacter error"); + SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error"); Attr.resize(Attr.size() + 1); if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead)) - SLog += StringFromFormat("WriteConsoleOutputAttribute error"); + SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error"); // Break on error if (cAttrRead == 0) break; @@ -223,9 +219,9 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool for (size_t i = 0; i < Attr.size(); i++) { if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten)) - SLog += StringFromFormat("WriteConsoleOutputCharacter error"); + SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error"); if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten)) - SLog += StringFromFormat("WriteConsoleOutputAttribute error"); + SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error"); BytesWritten += cAttrWritten; coordScreen = GetCoordinates(BytesWritten, LBufWidth); @@ -245,16 +241,6 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text) { #if defined(_WIN32) - /* - const int MAX_BYTES = 1024*10; - char Str[MAX_BYTES]; - va_list ArgPtr; - int Cnt; - va_start(ArgPtr, Text); - Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr); - va_end(ArgPtr); - */ - DWORD cCharsWritten; WORD Color; switch (Level) diff --git a/src/common/console_listener.h b/src/common/console_listener.h index 3c0e420c6..ebd90a105 100644 --- a/src/common/console_listener.h +++ b/src/common/console_listener.h @@ -26,7 +26,7 @@ public: #ifdef _WIN32 COORD GetCoordinates(int BytesRead, int BufferWidth); #endif - void Log(LogTypes::LOG_LEVELS, const char *Text); + void Log(LogTypes::LOG_LEVELS, const char *Text) override; void ClearScreen(bool Cursor = true); private: diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp new file mode 100644 index 000000000..7a2c50ac8 --- /dev/null +++ b/src/common/emu_window.cpp @@ -0,0 +1,17 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "emu_window.h" + +void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { + HID_User::PadState mapped_key = KeyMap::GetPadKey(key); + + HID_User::PadButtonPress(mapped_key); +} + +void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) { + HID_User::PadState mapped_key = KeyMap::GetPadKey(key); + + HID_User::PadButtonRelease(mapped_key); +} diff --git a/src/common/emu_window.h b/src/common/emu_window.h index 5e2c33d7a..4d09acb8b 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h @@ -6,6 +6,8 @@ #include "common/common.h" #include "common/scm_rev.h" +#include "common/string_util.h" +#include "common/key_map.h" // Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, // QGLWidget, GLFW, etc...) @@ -14,7 +16,7 @@ class EmuWindow public: /// Data structure to store an emuwindow configuration - struct Config{ + struct WindowConfig { bool fullscreen; int res_width; int res_height; @@ -32,11 +34,19 @@ public: /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread virtual void DoneCurrent() = 0; - Config GetConfig() const { + virtual void ReloadSetKeymaps() = 0; + + /// Signals a key press action to the HID module + static void KeyPressed(KeyMap::HostDeviceKey key); + + /// Signals a key release action to the HID module + static void KeyReleased(KeyMap::HostDeviceKey key); + + WindowConfig GetConfig() const { return m_config; } - void SetConfig(const Config& val) { + void SetConfig(const WindowConfig& val) { m_config = val; } @@ -65,11 +75,11 @@ public: } protected: - EmuWindow() : m_client_area_width(640), m_client_area_height(480) { - char window_title[255]; - sprintf(window_title, "Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); - m_window_title = window_title; - } + EmuWindow(): + m_client_area_width(640), + m_client_area_height(480), + m_window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc)) + {} virtual ~EmuWindow() {} std::string m_window_title; ///< Current window title, should be used by window impl. @@ -78,6 +88,6 @@ protected: int m_client_area_height; ///< Current client height, should be set by window impl. private: - Config m_config; ///< Internal configuration + WindowConfig m_config; ///< Internal configuration }; diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp index 66dae4935..9cd0398ed 100644 --- a/src/common/extended_trace.cpp +++ b/src/common/extended_trace.cpp @@ -278,7 +278,7 @@ void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack) GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo); GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo); - etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n"); + etfprint(file, " " + Common::TStrToUTF8(srcInfo) + " : " + Common::TStrToUTF8(symInfo) + "\n"); } void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp index a9d19477d..63580f688 100644 --- a/src/common/file_search.cpp +++ b/src/common/file_search.cpp @@ -4,15 +4,13 @@ #include "common/common.h" -#include "common/common_paths.h" + #ifndef _WIN32 -#include <sys/types.h> #include <dirent.h> #else #include <windows.h> #endif -#include <string> #include <algorithm> #include "common/file_search.h" @@ -35,10 +33,10 @@ CFileSearch::CFileSearch(const CFileSearch::XStringVector& _rSearchStrings, cons void CFileSearch::FindFiles(const std::string& _searchString, const std::string& _strPath) { std::string GCMSearchPath; - BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); + Common::BuildCompleteFilename(GCMSearchPath, _strPath, _searchString); #ifdef _WIN32 WIN32_FIND_DATA findData; - HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData); + HANDLE FindFirst = FindFirstFile(Common::UTF8ToTStr(GCMSearchPath).c_str(), &findData); if (FindFirst != INVALID_HANDLE_VALUE) { @@ -49,7 +47,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string& if (findData.cFileName[0] != '.') { std::string strFilename; - BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName)); + Common::BuildCompleteFilename(strFilename, _strPath, Common::TStrToUTF8(findData.cFileName)); m_FileNames.push_back(strFilename); } diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index b6ff2e40b..35da07306 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -4,9 +4,7 @@ #include "common/common.h" -#include "common/common_paths.h" #include "common/file_util.h" -#include "common/string_util.h" #ifdef _WIN32 #include <windows.h> @@ -15,11 +13,9 @@ #include <commdlg.h> // for GetSaveFileName #include <io.h> #include <direct.h> // getcwd +#include <tchar.h> #else -#include <cerrno> -#include <cstdlib> #include <sys/param.h> -#include <sys/types.h> #include <dirent.h> #endif @@ -32,8 +28,6 @@ #include <algorithm> #include <sys/stat.h> -#include "common/string_util.h" - #ifndef S_ISDIR #define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR) #endif @@ -46,7 +40,7 @@ // This namespace has various generic functions related to files and paths. // The code still needs a ton of cleanup. // REMEMBER: strdup considered harmful! -namespace File +namespace FileUtil { // Remove any ending forward slashes from directory paths @@ -71,7 +65,7 @@ bool Exists(const std::string &filename) StripTailDirSlashes(copy); #ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); + int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info); #else int result = stat64(copy.c_str(), &file_info); #endif @@ -88,7 +82,7 @@ bool IsDirectory(const std::string &filename) StripTailDirSlashes(copy); #ifdef _WIN32 - int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info); + int result = _tstat64(Common::UTF8ToTStr(copy).c_str(), &file_info); #else int result = stat64(copy.c_str(), &file_info); #endif @@ -124,7 +118,7 @@ bool Delete(const std::string &filename) } #ifdef _WIN32 - if (!DeleteFile(UTF8ToTStr(filename).c_str())) + if (!DeleteFile(Common::UTF8ToTStr(filename).c_str())) { WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", filename.c_str(), GetLastErrorMsg()); @@ -146,7 +140,7 @@ bool CreateDir(const std::string &path) { INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); #ifdef _WIN32 - if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL)) + if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), NULL)) return true; DWORD error = GetLastError(); if (error == ERROR_ALREADY_EXISTS) @@ -179,7 +173,7 @@ bool CreateFullPath(const std::string &fullPath) int panicCounter = 100; INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); - if (File::Exists(fullPath)) + if (FileUtil::Exists(fullPath)) { INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); return true; @@ -197,8 +191,10 @@ bool CreateFullPath(const std::string &fullPath) // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") std::string const subPath(fullPath.substr(0, position + 1)); - if (!File::IsDirectory(subPath)) - File::CreateDir(subPath); + if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) { + ERROR_LOG(COMMON, "CreateFullPath: directory creation failed"); + return false; + } // A safety check panicCounter--; @@ -218,14 +214,14 @@ bool DeleteDir(const std::string &filename) INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); // check if a directory - if (!File::IsDirectory(filename)) + if (!FileUtil::IsDirectory(filename)) { ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); return false; } #ifdef _WIN32 - if (::RemoveDirectory(UTF8ToTStr(filename).c_str())) + if (::RemoveDirectory(Common::UTF8ToTStr(filename).c_str())) return true; #else if (rmdir(filename.c_str()) == 0) @@ -254,7 +250,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) INFO_LOG(COMMON, "Copy: %s --> %s", srcFilename.c_str(), destFilename.c_str()); #ifdef _WIN32 - if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE)) + if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE)) return true; ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", @@ -342,7 +338,7 @@ u64 GetSize(const std::string &filename) struct stat64 buf; #ifdef _WIN32 - if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0) + if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0) #else if (stat64(filename.c_str(), &buf) == 0) #endif @@ -393,7 +389,7 @@ bool CreateEmptyFile(const std::string &filename) { INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); - if (!File::IOFile(filename, "wb")) + if (!FileUtil::IOFile(filename, "wb")) { ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", filename.c_str(), GetLastErrorMsg()); @@ -415,7 +411,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) // Find the first file in the directory. WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { FindClose(hFind); @@ -425,7 +421,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) do { FSTEntry entry; - const std::string virtualName(TStrToUTF8(ffd.cFileName)); + const std::string virtualName(Common::TStrToUTF8(ffd.cFileName)); #else struct dirent dirent, *result = NULL; @@ -482,7 +478,7 @@ bool DeleteDirRecursively(const std::string &directory) #ifdef _WIN32 // Find the first file in the directory. WIN32_FIND_DATA ffd; - HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd); + HANDLE hFind = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); if (hFind == INVALID_HANDLE_VALUE) { @@ -493,7 +489,7 @@ bool DeleteDirRecursively(const std::string &directory) // windows loop do { - const std::string virtualName(TStrToUTF8(ffd.cFileName)); + const std::string virtualName(Common::TStrToUTF8(ffd.cFileName)); #else struct dirent dirent, *result = NULL; DIR *dirp = opendir(directory.c_str()); @@ -526,7 +522,7 @@ bool DeleteDirRecursively(const std::string &directory) } else { - if (!File::Delete(newPath)) + if (!FileUtil::Delete(newPath)) { #ifndef _WIN32 closedir(dirp); @@ -543,7 +539,7 @@ bool DeleteDirRecursively(const std::string &directory) } closedir(dirp); #endif - File::DeleteDir(directory); + FileUtil::DeleteDir(directory); return true; } @@ -553,8 +549,8 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) { #ifndef _WIN32 if (source_path == dest_path) return; - if (!File::Exists(source_path)) return; - if (!File::Exists(dest_path)) File::CreateFullPath(dest_path); + if (!FileUtil::Exists(source_path)) return; + if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path); struct dirent dirent, *result = NULL; DIR *dirp = opendir(source_path.c_str()); @@ -576,10 +572,10 @@ void CopyDir(const std::string &source_path, const std::string &dest_path) { source += '/'; dest += '/'; - if (!File::Exists(dest)) File::CreateFullPath(dest); + if (!FileUtil::Exists(dest)) FileUtil::CreateFullPath(dest); CopyDir(source, dest); } - else if (!File::Exists(dest)) File::Copy(source, dest); + else if (!FileUtil::Exists(dest)) FileUtil::Copy(source, dest); } closedir(dirp); #endif @@ -631,7 +627,7 @@ std::string& GetExeDirectory() { TCHAR Dolphin_exe_Path[2048]; GetModuleFileName(NULL, Dolphin_exe_Path, 2048); - DolphinPath = TStrToUTF8(Dolphin_exe_Path); + DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path); DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); } return DolphinPath; @@ -655,7 +651,7 @@ std::string GetSysDirectory() return sysDir; } -// Returns a string with a Dolphin data dir or file in the user's home +// Returns a string with a Citra data dir or file in the user's home // directory. To be used in "multi-user" mode (that is, installed). const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath) { @@ -667,7 +663,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new #ifdef _WIN32 paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; #else - if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) + if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; else paths[D_USER_IDX] = std::string(getenv("HOME") ? @@ -675,27 +671,28 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP; #endif - paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; - paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; + paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; } if (!newPath.empty()) { - if (!File::IsDirectory(newPath)) + if (!FileUtil::IsDirectory(newPath)) { WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); return paths[DirIDX]; @@ -708,43 +705,44 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new switch (DirIDX) { case D_ROOT_IDX: - paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; - paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; - paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; + paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; + paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP; + paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF; break; case D_USER_IDX: - paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; - paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; - paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; - paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; - paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP; + paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP; + paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP; + paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; + paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; + paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; - paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; + paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP; - paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; - paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; + paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP; paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP; - paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; break; case D_CONFIG_IDX: - paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; - paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; - paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; + paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG; + paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG; + paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG; break; case D_DUMP_IDX: - paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; - paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; - paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; + paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP; + paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP; + paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP; break; case D_LOGS_IDX: @@ -757,25 +755,25 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new //std::string GetThemeDir(const std::string& theme_name) //{ -// std::string dir = File::GetUserPath(D_THEMES_IDX) + theme_name + "/"; +// std::string dir = FileUtil::GetUserPath(D_THEMES_IDX) + theme_name + "/"; // //#if !defined(_WIN32) // // If theme does not exist in user's dir load from shared directory -// if (!File::Exists(dir)) +// if (!FileUtil::Exists(dir)) // dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; //#endif // // return dir; //} -bool WriteStringToFile(bool text_file, const std::string &str, const char *filename) +size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename) { - return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); + return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); } -bool ReadFileToString(bool text_file, const char *filename, std::string &str) +size_t ReadFileToString(bool text_file, const char *filename, std::string &str) { - File::IOFile file(filename, text_file ? "r" : "rb"); + FileUtil::IOFile file(filename, text_file ? "r" : "rb"); auto const f = file.GetHandle(); if (!f) @@ -785,6 +783,48 @@ bool ReadFileToString(bool text_file, const char *filename, std::string &str) return file.ReadArray(&str[0], str.size()); } +/** + * Splits the filename into 8.3 format + * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename + * @param filename The normal filename to use + * @param short_name A 9-char array in which the short name will be written + * @param extension A 4-char array in which the extension will be written + */ +void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, + std::array<char, 4>& extension) { + const std::string forbidden_characters = ".\"/\\[]:;=, "; + + // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces. + short_name = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}; + extension = {' ', ' ', ' ', '\0'}; + + std::string::size_type point = filename.rfind('.'); + if (point == filename.size() - 1) + point = filename.rfind('.', point); + + // Get short name. + int j = 0; + for (char letter : filename.substr(0, point)) { + if (forbidden_characters.find(letter, 0) != std::string::npos) + continue; + if (j == 8) { + // TODO(Link Mauve): also do that for filenames containing a space. + // TODO(Link Mauve): handle multiple files having the same short name. + short_name[6] = '~'; + short_name[7] = '1'; + break; + } + short_name[j++] = toupper(letter); + } + + // Get extension. + if (point != std::string::npos) { + j = 0; + for (char letter : filename.substr(point + 1, 3)) + extension[j++] = toupper(letter); + } +} + IOFile::IOFile() : m_file(NULL), m_good(true) {} @@ -826,7 +866,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[]) { Close(); #ifdef _WIN32 - _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()); + _tfopen_s(&m_file, Common::UTF8ToTStr(filename).c_str(), Common::UTF8ToTStr(openmode).c_str()); #else m_file = fopen(filename.c_str(), openmode); #endif @@ -861,7 +901,7 @@ void IOFile::SetHandle(std::FILE* file) u64 IOFile::GetSize() { if (IsOpen()) - return File::GetSize(m_file); + return FileUtil::GetSize(m_file); else return 0; } diff --git a/src/common/file_util.h b/src/common/file_util.h index 0871734d4..173ce6623 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -4,11 +4,12 @@ #pragma once +#include <array> #include <fstream> #include <cstdio> +#include <cstring> #include <string> #include <vector> -#include <string.h> #include "common/common.h" #include "common/string_util.h" @@ -25,6 +26,7 @@ enum { D_SHADERS_IDX, D_STATESAVES_IDX, D_SCREENSHOTS_IDX, + D_SDMC_IDX, D_HIRESTEXTURES_IDX, D_DUMP_IDX, D_DUMPFRAMES_IDX, @@ -43,10 +45,10 @@ enum { NUM_PATH_INDICES }; -namespace File +namespace FileUtil { -// FileSystem tree node/ +// FileSystem tree node/ struct FSTEntry { bool isDirectory; @@ -84,13 +86,13 @@ bool Delete(const std::string &filename); // Deletes a directory filename, returns true on success bool DeleteDir(const std::string &filename); -// renames file srcFilename to destFilename, returns true on success +// renames file srcFilename to destFilename, returns true on success bool Rename(const std::string &srcFilename, const std::string &destFilename); -// copies file srcFilename to destFilename, returns true on success +// copies file srcFilename to destFilename, returns true on success bool Copy(const std::string &srcFilename, const std::string &destFilename); -// creates an empty file filename, returns true on success +// creates an empty file filename, returns true on success bool CreateEmptyFile(const std::string &filename); // Scans the directory tree gets, starting from _Directory and adds the @@ -109,7 +111,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path); // Set the current directory to given directory bool SetCurrentDir(const std::string &directory); -// Returns a pointer to a string with a Dolphin data dir in the user's home +// Returns a pointer to a string with a Citra data dir in the user's home // directory. To be used in "multi-user" mode (that is, installed). const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); @@ -127,8 +129,18 @@ std::string GetBundleDirectory(); std::string &GetExeDirectory(); #endif -bool WriteStringToFile(bool text_file, const std::string &str, const char *filename); -bool ReadFileToString(bool text_file, const char *filename, std::string &str); +size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename); +size_t ReadFileToString(bool text_file, const char *filename, std::string &str); + +/** + * Splits the filename into 8.3 format + * Loosely implemented following https://en.wikipedia.org/wiki/8.3_filename + * @param filename The normal filename to use + * @param short_name A 9-char array in which the short name will be written + * @param extension A 4-char array in which the extension will be written + */ +void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, + std::array<char, 4>& extension); // simple wrapper for cstdlib file functions to // hopefully will make error checking easier @@ -141,39 +153,51 @@ public: IOFile(const std::string& filename, const char openmode[]); ~IOFile(); - + IOFile(IOFile&& other); IOFile& operator=(IOFile&& other); - + void Swap(IOFile& other); bool Open(const std::string& filename, const char openmode[]); bool Close(); template <typename T> - bool ReadArray(T* data, size_t length) + size_t ReadArray(T* data, size_t length) { - if (!IsOpen() || length != std::fread(data, sizeof(T), length, m_file)) + if (!IsOpen()) { m_good = false; + return -1; + } - return m_good; + size_t items_read = std::fread(data, sizeof(T), length, m_file); + if (items_read != length) + m_good = false; + + return items_read; } template <typename T> - bool WriteArray(const T* data, size_t length) + size_t WriteArray(const T* data, size_t length) { - if (!IsOpen() || length != std::fwrite(data, sizeof(T), length, m_file)) + if (!IsOpen()) { + m_good = false; + return -1; + } + + size_t items_written = std::fwrite(data, sizeof(T), length, m_file); + if (items_written != length) m_good = false; - return m_good; + return items_written; } - bool ReadBytes(void* data, size_t length) + size_t ReadBytes(void* data, size_t length) { return ReadArray(reinterpret_cast<char*>(data), length); } - bool WriteBytes(const void* data, size_t length) + size_t WriteBytes(const void* data, size_t length) { return WriteArray(reinterpret_cast<const char*>(data), length); } @@ -213,7 +237,7 @@ template <typename T> void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) { #ifdef _WIN32 - fstream.open(UTF8ToTStr(filename).c_str(), openmode); + fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); #else fstream.open(filename.c_str(), openmode); #endif diff --git a/src/common/fixed_size_queue.h b/src/common/fixed_size_queue.h deleted file mode 100644 index 1e3a5dea6..000000000 --- a/src/common/fixed_size_queue.h +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -// STL-look-a-like interface, but name is mixed case to distinguish it clearly from the -// real STL classes. - -// Not fully featured, no safety checking yet. Add features as needed. - -// TODO: "inline" storage? - -template <class T, int N> -class fixed_size_queue.h -{ - T *storage; - int head; - int tail; - int count; // sacrifice 4 bytes for a simpler implementation. may optimize away in the future. - - // Make copy constructor private for now. - fixed_size_queue.h(fixed_size_queue.h &other) { } - -public: - fixed_size_queue.h() - { - storage = new T[N]; - clear(); - } - - ~fixed_size_queue.h() - { - delete [] storage; - } - - void clear() { - head = 0; - tail = 0; - count = 0; - } - - void push(T t) { - storage[tail] = t; - tail++; - if (tail == N) - tail = 0; - count++; - } - - void pop() { - head++; - if (head == N) - head = 0; - count--; - } - - T pop_front() { - const T &temp = storage[head]; - pop(); - return temp; - } - - T &front() { return storage[head]; } - const T &front() const { return storage[head]; } - - size_t size() const { - return count; - } -}; diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp new file mode 100644 index 000000000..309caab98 --- /dev/null +++ b/src/common/key_map.cpp @@ -0,0 +1,25 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "key_map.h" +#include <map> + +namespace KeyMap { + +static std::map<HostDeviceKey, HID_User::PadState> key_map; +static int next_device_id = 0; + +int NewDeviceId() { + return next_device_id++; +} + +void SetKeyMapping(HostDeviceKey key, HID_User::PadState padState) { + key_map[key].hex = padState.hex; +} + +HID_User::PadState GetPadKey(HostDeviceKey key) { + return key_map[key]; +} + +} diff --git a/src/common/key_map.h b/src/common/key_map.h new file mode 100644 index 000000000..bf72362c0 --- /dev/null +++ b/src/common/key_map.h @@ -0,0 +1,45 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/hid_user.h" + +namespace KeyMap { + +/** + * Represents a key for a specific host device. + */ +struct HostDeviceKey { + int key_code; + int device_id; ///< Uniquely identifies a host device + + bool operator < (const HostDeviceKey &other) const { + if (device_id == other.device_id) { + return key_code < other.key_code; + } + return device_id < other.device_id; + } + + bool operator == (const HostDeviceKey &other) const { + return device_id == other.device_id && key_code == other.key_code; + } +}; + +/** + * Generates a new device id, which uniquely identifies a host device within KeyMap. + */ +int NewDeviceId(); + +/** + * Maps a device-specific key to a PadState. + */ +void SetKeyMapping(HostDeviceKey key, HID_User::PadState padState); + +/** + * Gets the PadState that's mapped to the provided device-specific key. + */ +HID_User::PadState GetPadKey(HostDeviceKey key); + +} diff --git a/src/common/log.h b/src/common/log.h index 291534c67..bfd73f8a5 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -28,6 +28,7 @@ enum LOG_TYPE { COMMANDPROCESSOR, COMMON, CONSOLE, + CONFIG, DISCIO, FILEMON, DSPHLE, diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index 4e1cb60bd..4d590d98f 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp @@ -8,7 +8,6 @@ #include "common/console_listener.h" #include "common/timer.h" #include "common/thread.h" -#include "common/file_util.h" void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, const char* function, const char* fmt, ...) @@ -31,6 +30,7 @@ LogManager::LogManager() m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log"); m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot"); m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common"); + m_Log[LogTypes::CONFIG] = new LogContainer("CONFIG", "Configuration"); m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO"); m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor"); m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad"); @@ -76,7 +76,7 @@ LogManager::LogManager() m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); - m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str()); + m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str()); m_consoleLog = new ConsoleListener(); m_debuggerLog = new DebuggerLogListener(); @@ -121,7 +121,7 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners()) return; - CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); + Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); static const char level_to_char[7] = "ONEWID"; sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, diff --git a/src/common/log_manager.h b/src/common/log_manager.h index ce62d0361..de1d16ee5 100644 --- a/src/common/log_manager.h +++ b/src/common/log_manager.h @@ -30,7 +30,7 @@ class FileLogListener : public LogListener public: FileLogListener(const char *filename); - void Log(LogTypes::LOG_LEVELS, const char *msg); + void Log(LogTypes::LOG_LEVELS, const char *msg) override; bool IsValid() { return !m_logfile.fail(); } bool IsEnabled() const { return m_enable; } @@ -47,7 +47,7 @@ private: class DebuggerLogListener : public LogListener { public: - void Log(LogTypes::LOG_LEVELS, const char *msg); + void Log(LogTypes::LOG_LEVELS, const char *msg) override; }; class LogContainer diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp index 82eceab00..ab0e6b75c 100644 --- a/src/common/math_util.cpp +++ b/src/common/math_util.cpp @@ -6,8 +6,7 @@ #include "common/common.h" #include "common/math_util.h" -#include <cmath> -#include <numeric> +#include <numeric> // Necessary on OS X, but not Linux namespace MathUtil { diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp index b76ac92d3..40d9c03a2 100644 --- a/src/common/mem_arena.cpp +++ b/src/common/mem_arena.cpp @@ -22,11 +22,7 @@ #include "common/string_util.h" #ifndef _WIN32 -#include <sys/stat.h> #include <fcntl.h> -#include <unistd.h> -#include <cerrno> -#include <cstring> #ifdef ANDROID #include <sys/ioctl.h> #include <linux/ashmem.h> @@ -143,7 +139,7 @@ void MemArena::GrabLowMemSpace(size_t size) // a bit more. for (int i = 0; i < 10000; i++) { - std::string file_name = StringFromFormat("/citramem.%d", i); + std::string file_name = Common::StringFromFormat("/citramem.%d", i); fd = shm_open(file_name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); if (fd != -1) { diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp index e01e63175..bab7d9f7a 100644 --- a/src/common/memory_util.cpp +++ b/src/common/memory_util.cpp @@ -10,9 +10,6 @@ #ifdef _WIN32 #include <windows.h> #include <psapi.h> -#else -#include <cerrno> -#include <cstdio> #endif #if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) @@ -190,7 +187,7 @@ std::string MemUsage() if (NULL == hProcess) return "MemUsage Error"; if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) - Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); + Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); CloseHandle(hProcess); return Ret; diff --git a/src/common/msg_handler.cpp b/src/common/msg_handler.cpp index 3e02ec4d7..b3556aaa8 100644 --- a/src/common/msg_handler.cpp +++ b/src/common/msg_handler.cpp @@ -72,7 +72,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...) va_list args; va_start(args, format); - CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); + Common::CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); va_end(args); ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index c1f22bda3..54943d306 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp @@ -3,34 +3,29 @@ // Refer to the license.txt file included. #include <algorithm> -#include <cstdlib> -#include <cstdio> #include "common/common.h" -#include "common/common_paths.h" #include "common/string_util.h" #ifdef _WIN32 #include <Windows.h> + #include <codecvt> #else - #include <cerrno> #include <iconv.h> #endif +namespace Common { + /// Make a string lowercase -void LowerStr(char* str) { - for (int i = 0; str[i]; i++) { - str[i] = tolower(str[ i ]); - } +std::string ToLower(std::string str) { + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; } /// Make a string uppercase -void UpperStr(char* str) { - for (int i=0; i < strlen(str); i++) { - if(str[i] >= 'a' && str[i] <= 'z') { - str[i] &= 0xDF; - } - } +std::string ToUpper(std::string str) { + std::transform(str.begin(), str.end(), str.begin(), ::toupper); + return str; } // faster than sscanf @@ -192,9 +187,9 @@ bool TryParse(const std::string &str, u32 *const output) bool TryParse(const std::string &str, bool *const output) { - if ("1" == str || !strcasecmp("true", str.c_str())) + if ("1" == str || "true" == ToLower(str)) *output = true; - else if ("0" == str || !strcasecmp("false", str.c_str())) + else if ("0" == str || "false" == ToLower(str)) *output = false; else return false; @@ -202,13 +197,6 @@ bool TryParse(const std::string &str, bool *const output) return true; } -std::string StringFromInt(int value) -{ - char temp[16]; - sprintf(temp, "%i", value); - return temp; -} - std::string StringFromBool(bool value) { return value ? "True" : "False"; @@ -283,12 +271,17 @@ std::string TabsToSpaces(int tab_size, const std::string &in) std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) { - while(1) + size_t pos = 0; + + if (src == dest) + return result; + + while ((pos = result.find(src, pos)) != std::string::npos) { - size_t pos = result.find(src); - if (pos == std::string::npos) break; result.replace(pos, src.size(), dest); + pos += dest.length(); } + return result; } @@ -419,7 +412,19 @@ std::string UriEncode(const std::string & sSrc) #ifdef _WIN32 -std::string UTF16ToUTF8(const std::wstring& input) +std::string UTF16ToUTF8(const std::u16string& input) +{ + std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; + return convert.to_bytes(input); +} + +std::u16string UTF8ToUTF16(const std::string& input) +{ + std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; + return convert.from_bytes(input); +} + +static std::string UTF16ToUTF8(const std::wstring& input) { auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr); @@ -432,7 +437,7 @@ std::string UTF16ToUTF8(const std::wstring& input) return output; } -std::wstring CPToUTF16(u32 code_page, const std::string& input) +static std::wstring CPToUTF16(u32 code_page, const std::string& input) { auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0); @@ -445,7 +450,7 @@ std::wstring CPToUTF16(u32 code_page, const std::string& input) return output; } -std::wstring UTF8ToUTF16(const std::string& input) +std::wstring UTF8ToUTF16W(const std::string &input) { return CPToUTF16(CP_UTF8, input); } @@ -463,61 +468,123 @@ std::string CP1252ToUTF8(const std::string& input) #else template <typename T> -std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) +static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) { std::string result; iconv_t const conv_desc = iconv_open("UTF-8", fromcode); - if ((iconv_t)-1 == conv_desc) + if ((iconv_t)(-1) == conv_desc) { ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); + iconv_close(conv_desc); + return {}; } - else - { - size_t const in_bytes = sizeof(T) * input.size(); - size_t const out_buffer_size = 4 * in_bytes; - std::string out_buffer; - out_buffer.resize(out_buffer_size); + const size_t in_bytes = sizeof(T) * input.size(); + // Multiply by 4, which is the max number of bytes to encode a codepoint + const size_t out_buffer_size = 4 * in_bytes; - auto src_buffer = &input[0]; - size_t src_bytes = in_bytes; - auto dst_buffer = &out_buffer[0]; - size_t dst_bytes = out_buffer.size(); + std::string out_buffer; + out_buffer.resize(out_buffer_size); - while (src_bytes != 0) - { - size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, - &dst_buffer, &dst_bytes); + auto src_buffer = &input[0]; + size_t src_bytes = in_bytes; + auto dst_buffer = &out_buffer[0]; + size_t dst_bytes = out_buffer.size(); + + while (0 != src_bytes) + { + size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes, + &dst_buffer, &dst_bytes); - if ((size_t)-1 == iconv_result) + if (static_cast<size_t>(-1) == iconv_result) + { + if (EILSEQ == errno || EINVAL == errno) { - if (EILSEQ == errno || EINVAL == errno) + // Try to skip the bad character + if (0 != src_bytes) { - // Try to skip the bad character - if (src_bytes != 0) - { - --src_bytes; - ++src_buffer; - } - } - else - { - ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); - break; + --src_bytes; + ++src_buffer; } } + else + { + ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); + break; + } } + } - out_buffer.resize(out_buffer_size - dst_bytes); - out_buffer.swap(result); - + out_buffer.resize(out_buffer_size - dst_bytes); + out_buffer.swap(result); + + iconv_close(conv_desc); + + return result; +} + +std::u16string UTF8ToUTF16(const std::string& input) +{ + std::u16string result; + + iconv_t const conv_desc = iconv_open("UTF-16", "UTF-8"); + if ((iconv_t)(-1) == conv_desc) + { + ERROR_LOG(COMMON, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); iconv_close(conv_desc); + return {}; + } + + const size_t in_bytes = sizeof(char) * input.size(); + // Multiply by 4, which is the max number of bytes to encode a codepoint + const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes; + + std::u16string out_buffer; + out_buffer.resize(out_buffer_size); + + char* src_buffer = const_cast<char*>(&input[0]); + size_t src_bytes = in_bytes; + char* dst_buffer = (char*)(&out_buffer[0]); + size_t dst_bytes = out_buffer.size(); + + while (0 != src_bytes) + { + size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes, + &dst_buffer, &dst_bytes); + + if (static_cast<size_t>(-1) == iconv_result) + { + if (EILSEQ == errno || EINVAL == errno) + { + // Try to skip the bad character + if (0 != src_bytes) + { + --src_bytes; + ++src_buffer; + } + } + else + { + ERROR_LOG(COMMON, "iconv failure [UTF-8]: %s", strerror(errno)); + break; + } + } } + + out_buffer.resize(out_buffer_size - dst_bytes); + out_buffer.swap(result); + + iconv_close(conv_desc); return result; } +std::string UTF16ToUTF8(const std::u16string& input) +{ + return CodeToUTF8("UTF-16", input); +} + std::string CP1252ToUTF8(const std::string& input) { //return CodeToUTF8("CP1252//TRANSLIT", input); @@ -531,17 +598,6 @@ std::string SHIFTJISToUTF8(const std::string& input) return CodeToUTF8("SJIS", input); } -std::string UTF16ToUTF8(const std::wstring& input) -{ - std::string result = - // CodeToUTF8("UCS-2", input); - // CodeToUTF8("UCS-2LE", input); - // CodeToUTF8("UTF-16", input); - CodeToUTF8("UTF-16LE", input); - - // TODO: why is this needed? - result.erase(std::remove(result.begin(), result.end(), 0x00), result.end()); - return result; -} - #endif + +} diff --git a/src/common/string_util.h b/src/common/string_util.h index ba4cd363e..787a5663f 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -12,11 +12,13 @@ #include "common/common.h" +namespace Common { + /// Make a string lowercase -void LowerStr(char* str); +std::string ToLower(std::string str); /// Make a string uppercase -void UpperStr(char* str); +std::string ToUpper(std::string str); std::string StringFromFormat(const char* format, ...); // Cheap! @@ -52,7 +54,6 @@ std::string ThousandSeparate(I value, int spaces = 0) return oss.str(); } -std::string StringFromInt(int value); std::string StringFromBool(bool value); bool TryParse(const std::string &str, bool *output); @@ -88,20 +89,22 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st std::string UriDecode(const std::string & sSrc); std::string UriEncode(const std::string & sSrc); +std::string UTF16ToUTF8(const std::u16string& input); +std::u16string UTF8ToUTF16(const std::string& input); + std::string CP1252ToUTF8(const std::string& str); std::string SHIFTJISToUTF8(const std::string& str); -std::string UTF16ToUTF8(const std::wstring& str); #ifdef _WIN32 -std::wstring UTF8ToUTF16(const std::string& str); +std::wstring UTF8ToUTF16W(const std::string& str); #ifdef _UNICODE inline std::string TStrToUTF8(const std::wstring& str) { return UTF16ToUTF8(str); } inline std::wstring UTF8ToTStr(const std::string& str) -{ return UTF8ToUTF16(str); } +{ return UTF8ToUTF16W(str); } #else inline std::string TStrToUTF8(const std::string& str) { return str; } @@ -111,3 +114,5 @@ inline std::string UTF8ToTStr(const std::string& str) #endif #endif + +} diff --git a/src/common/swap.h b/src/common/swap.h index 123019fd1..4f8f39efb 100644 --- a/src/common/swap.h +++ b/src/common/swap.h @@ -85,7 +85,6 @@ public: return *this; } - operator long() const { return (long)swap(); } operator s8() const { return (s8)swap(); } operator u8() const { return (u8)swap(); } operator s16() const { return (s16)swap(); } diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 830795182..60d8ed075 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include "common/thread.h" -#include "common/common.h" #ifdef __APPLE__ #include <mach/mach.h> diff --git a/src/common/timer.cpp b/src/common/timer.cpp index f8e1fadca..ded4a344e 100644 --- a/src/common/timer.cpp +++ b/src/common/timer.cpp @@ -169,7 +169,6 @@ std::string Timer::GetTimeFormatted() { time_t sysTime; struct tm * gmTime; - char formattedTime[13]; char tmp[13]; time(&sysTime); @@ -181,14 +180,12 @@ std::string Timer::GetTimeFormatted() #ifdef _WIN32 struct timeb tp; (void)::ftime(&tp); - sprintf(formattedTime, "%s:%03i", tmp, tp.millitm); + return StringFromFormat("%s:%03i", tmp, tp.millitm); #else struct timeval t; (void)gettimeofday(&t, NULL); - sprintf(formattedTime, "%s:%03d", tmp, (int)(t.tv_usec / 1000)); + return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000)); #endif - - return std::string(formattedTime); } // Returns a timestamp with decimals for precise time comparisons diff --git a/src/common/utf8.cpp b/src/common/utf8.cpp index c83824d35..be4ebc855 100644 --- a/src/common/utf8.cpp +++ b/src/common/utf8.cpp @@ -19,12 +19,8 @@ #endif #include <cstdlib> -#include <cstdio> #include <cstring> -#include <cstdarg> - #include <algorithm> -#include <string> #include "common/common_types.h" #include "common/utf8.h" diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1f358ec8d..f41d52e80 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,28 +1,28 @@ set(SRCS arm/disassembler/arm_disasm.cpp arm/disassembler/load_symbol_map.cpp - arm/interpreter/mmu/arm1176jzf_s_mmu.cpp - arm/interpreter/mmu/cache.cpp - arm/interpreter/mmu/maverick.cpp - arm/interpreter/mmu/rb.cpp - arm/interpreter/mmu/sa_mmu.cpp - arm/interpreter/mmu/tlb.cpp - arm/interpreter/mmu/wb.cpp - arm/interpreter/mmu/xscale_copro.cpp - arm/interpreter/vfp/vfp.cpp - arm/interpreter/vfp/vfpdouble.cpp - arm/interpreter/vfp/vfpinstr.cpp - arm/interpreter/vfp/vfpsingle.cpp + arm/dyncom/arm_dyncom.cpp + arm/dyncom/arm_dyncom_dec.cpp + arm/dyncom/arm_dyncom_interpreter.cpp + arm/dyncom/arm_dyncom_run.cpp + arm/dyncom/arm_dyncom_thumb.cpp arm/interpreter/arm_interpreter.cpp arm/interpreter/armcopro.cpp arm/interpreter/armemu.cpp arm/interpreter/arminit.cpp - arm/interpreter/armmmu.cpp - arm/interpreter/armos.cpp arm/interpreter/armsupp.cpp arm/interpreter/armvirt.cpp arm/interpreter/thumbemu.cpp + arm/skyeye_common/vfp/vfp.cpp + arm/skyeye_common/vfp/vfpdouble.cpp + arm/skyeye_common/vfp/vfpinstr.cpp + arm/skyeye_common/vfp/vfpsingle.cpp file_sys/archive_romfs.cpp + file_sys/archive_sdmc.cpp + file_sys/file_romfs.cpp + file_sys/file_sdmc.cpp + file_sys/directory_romfs.cpp + file_sys/directory_sdmc.cpp hle/kernel/address_arbiter.cpp hle/kernel/archive.cpp hle/kernel/event.cpp @@ -30,15 +30,24 @@ set(SRCS hle/kernel/mutex.cpp hle/kernel/shared_memory.cpp hle/kernel/thread.cpp - hle/service/apt.cpp - hle/service/fs.cpp - hle/service/gsp.cpp - hle/service/hid.cpp - hle/service/ndm.cpp + hle/service/ac_u.cpp + hle/service/apt_u.cpp + hle/service/cfg_u.cpp + hle/service/dsp_dsp.cpp + hle/service/err_f.cpp + hle/service/fs_user.cpp + hle/service/frd_u.cpp + hle/service/gsp_gpu.cpp + hle/service/hid_user.cpp + hle/service/mic_u.cpp + hle/service/ndm_u.cpp + hle/service/nwm_uds.cpp + hle/service/ptm_u.cpp hle/service/service.cpp + hle/service/soc_u.cpp hle/service/srv.cpp + hle/service/ssl_c.cpp hle/config_mem.cpp - hle/coprocessor.cpp hle/hle.cpp hle/svc.cpp hw/gpu.cpp @@ -51,32 +60,40 @@ set(SRCS core_timing.cpp mem_map.cpp mem_map_funcs.cpp + settings.cpp system.cpp ) set(HEADERS arm/disassembler/arm_disasm.h arm/disassembler/load_symbol_map.h - arm/interpreter/mmu/arm1176jzf_s_mmu.h - arm/interpreter/mmu/cache.h - arm/interpreter/mmu/rb.h - arm/interpreter/mmu/sa_mmu.h - arm/interpreter/mmu/tlb.h - arm/interpreter/mmu/wb.h - arm/interpreter/vfp/asm_vfp.h - arm/interpreter/vfp/vfp.h - arm/interpreter/vfp/vfp_helper.h + arm/dyncom/arm_dyncom.h + arm/dyncom/arm_dyncom_dec.h + arm/dyncom/arm_dyncom_interpreter.h + arm/dyncom/arm_dyncom_run.h + arm/dyncom/arm_dyncom_thumb.h arm/interpreter/arm_interpreter.h - arm/interpreter/arm_regformat.h - arm/interpreter/armcpu.h - arm/interpreter/armdefs.h - arm/interpreter/armemu.h - arm/interpreter/armmmu.h - arm/interpreter/armos.h - arm/interpreter/skyeye_defs.h + arm/skyeye_common/arm_regformat.h + arm/skyeye_common/armcpu.h + arm/skyeye_common/armdefs.h + arm/skyeye_common/armemu.h + arm/skyeye_common/armmmu.h + arm/skyeye_common/armos.h + arm/skyeye_common/skyeye_defs.h + arm/skyeye_common/skyeye_types.h + arm/skyeye_common/vfp/asm_vfp.h + arm/skyeye_common/vfp/vfp.h + arm/skyeye_common/vfp/vfp_helper.h arm/arm_interface.h file_sys/archive.h file_sys/archive_romfs.h + file_sys/archive_sdmc.h + file_sys/file.h + file_sys/file_romfs.h + file_sys/file_sdmc.h + file_sys/directory.h + file_sys/directory_romfs.h + file_sys/directory_sdmc.h hle/kernel/address_arbiter.h hle/kernel/archive.h hle/kernel/event.h @@ -84,15 +101,24 @@ set(HEADERS hle/kernel/mutex.h hle/kernel/shared_memory.h hle/kernel/thread.h - hle/service/apt.h - hle/service/fs.h - hle/service/gsp.h - hle/service/hid.h - hle/service/ndm.h + hle/service/ac_u.h + hle/service/apt_u.h + hle/service/cfg_u.h + hle/service/dsp_dsp.h + hle/service/err_f.h + hle/service/fs_user.h + hle/service/frd_u.h + hle/service/gsp_gpu.h + hle/service/hid_user.h + hle/service/mic_u.h + hle/service/ndm_u.h + hle/service/nwm_uds.h + hle/service/ptm_u.h hle/service/service.h + hle/service/soc_u.h hle/service/srv.h + hle/service/ssl_c.h hle/config_mem.h - hle/coprocessor.h hle/function_wrappers.h hle/hle.h hle/svc.h @@ -105,6 +131,7 @@ set(HEADERS core.h core_timing.h mem_map.h + settings.h system.h ) diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 33e036cbf..45c720e16 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -260,14 +260,14 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn) // The "mov" instruction ignores the first operand (rn). rn_str[0] = 0; if ((flags & kNoOperand1) == 0) { - rn_str = StringFromFormat("r%d, ", rn); + rn_str = Common::StringFromFormat("r%d, ", rn); } // The following instructions do not write the result register (rd): // tst, teq, cmp, cmn. rd_str[0] = 0; if ((flags & kNoDest) == 0) { - rd_str = StringFromFormat("r%d, ", rd); + rd_str = Common::StringFromFormat("r%d, ", rd); } const char *sbit_str = ""; @@ -275,7 +275,7 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn) sbit_str = "s"; if (is_immed) { - return StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x", + return Common::StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x", opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed); } @@ -290,24 +290,24 @@ std::string ARM_Disasm::DisassembleALU(Opcode opcode, uint32_t insn) rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { - return StringFromFormat("%s%s%s\t%s%sr%d", + return Common::StringFromFormat("%s%s%s\t%s%sr%d", opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm); } const char *shift_name = shift_names[shift_type]; if (shift_is_reg) { - return StringFromFormat("%s%s%s\t%s%sr%d, %s r%d", + return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s r%d", opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm, shift_name, rs); } if (shift_amount == 0) { if (shift_type == 3) { - return StringFromFormat("%s%s%s\t%s%sr%d, RRX", + return Common::StringFromFormat("%s%s%s\t%s%sr%d, RRX", opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm); } shift_amount = 32; } - return StringFromFormat("%s%s%s\t%s%sr%d, %s #%u", + return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s #%u", opname, cond_to_str(cond), sbit_str, rd_str.c_str(), rn_str.c_str(), rm, shift_name, shift_amount); } @@ -325,20 +325,20 @@ std::string ARM_Disasm::DisassembleBranch(uint32_t addr, Opcode opcode, uint32_t offset += 8; addr += offset; const char *opname = opcode_names[opcode]; - return StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr); + return Common::StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr); } std::string ARM_Disasm::DisassembleBX(uint32_t insn) { uint8_t cond = (insn >> 28) & 0xf; uint8_t rn = insn & 0xf; - return StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn); + return Common::StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn); } std::string ARM_Disasm::DisassembleBKPT(uint32_t insn) { uint32_t immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); - return StringFromFormat("bkpt\t#%d", immed); + return Common::StringFromFormat("bkpt\t#%d", immed); } std::string ARM_Disasm::DisassembleCLZ(uint32_t insn) @@ -346,7 +346,7 @@ std::string ARM_Disasm::DisassembleCLZ(uint32_t insn) uint8_t cond = (insn >> 28) & 0xf; uint8_t rd = (insn >> 12) & 0xf; uint8_t rm = insn & 0xf; - return StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); + return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); } std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) @@ -376,7 +376,7 @@ std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) tmp_list[0] = 0; for (int ii = 0; ii < 16; ++ii) { if (reg_list & (1 << ii)) { - tmp_list += StringFromFormat("%sr%d", comma, ii); + tmp_list += Common::StringFromFormat("%sr%d", comma, ii); comma = ","; } } @@ -396,7 +396,7 @@ std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) } } - return StringFromFormat("%s%s%s\tr%d%s, {%s}%s", + return Common::StringFromFormat("%s%s%s\tr%d%s, {%s}%s", opname, cond_to_str(cond), addr_mode, rn, bang, tmp_list.c_str(), carret); } @@ -432,10 +432,10 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn) if (is_reg == 0) { if (is_pre) { if (offset == 0) { - return StringFromFormat("%s%s%s\tr%d, [r%d]", + return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", opname, cond_to_str(cond), byte, rd, rn); } else { - return StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", + return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", opname, cond_to_str(cond), byte, rd, rn, minus, offset, bang); } } else { @@ -443,7 +443,7 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn) if (write_back) transfer = "t"; - return StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u", + return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u", opname, cond_to_str(cond), byte, transfer, rd, rn, minus, offset); } } @@ -457,16 +457,16 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn) if (is_pre) { if (shift_amount == 0) { if (shift_type == 0) { - return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", + return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); } if (shift_type == 3) { - return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", + return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", opname, cond_to_str(cond), byte, rd, rn, minus, rm, bang); } shift_amount = 32; } - return StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", + return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", opname, cond_to_str(cond), byte, rd, rn, minus, rm, shift_name, shift_amount, bang); } @@ -477,17 +477,17 @@ std::string ARM_Disasm::DisassembleMem(uint32_t insn) if (shift_amount == 0) { if (shift_type == 0) { - return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d", + return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d", opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); } if (shift_type == 3) { - return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX", + return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX", opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm); } shift_amount = 32; } - return StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", + return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", opname, cond_to_str(cond), byte, transfer, rd, rn, minus, rm, shift_name, shift_amount); } @@ -528,22 +528,22 @@ std::string ARM_Disasm::DisassembleMemHalf(uint32_t insn) if (is_immed) { if (is_pre) { if (offset == 0) { - return StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); + return Common::StringFromFormat("%s%sh\tr%d, [r%d]", opname, cond_to_str(cond), rd, rn); } else { - return StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s", + return Common::StringFromFormat("%s%sh\tr%d, [r%d, #%s%u]%s", opname, cond_to_str(cond), rd, rn, minus, offset, bang); } } else { - return StringFromFormat("%s%sh\tr%d, [r%d], #%s%u", + return Common::StringFromFormat("%s%sh\tr%d, [r%d], #%s%u", opname, cond_to_str(cond), rd, rn, minus, offset); } } if (is_pre) { - return StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s", + return Common::StringFromFormat("%s%sh\tr%d, [r%d, %sr%d]%s", opname, cond_to_str(cond), rd, rn, minus, rm, bang); } else { - return StringFromFormat("%s%sh\tr%d, [r%d], %sr%d", + return Common::StringFromFormat("%s%sh\tr%d, [r%d], %sr%d", opname, cond_to_str(cond), rd, rn, minus, rm); } } @@ -558,7 +558,7 @@ std::string ARM_Disasm::DisassembleMCR(Opcode opcode, uint32_t insn) uint8_t crm = insn & 0xf; const char *opname = opcode_names[opcode]; - return StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", + return Common::StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", opname, cond_to_str(cond), cpnum, crd, crn, crm, opcode2); } @@ -572,7 +572,7 @@ std::string ARM_Disasm::DisassembleMLA(Opcode opcode, uint32_t insn) uint8_t bit_s = (insn >> 20) & 1; const char *opname = opcode_names[opcode]; - return StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", + return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs, rn); } @@ -586,7 +586,7 @@ std::string ARM_Disasm::DisassembleUMLAL(Opcode opcode, uint32_t insn) uint8_t bit_s = (insn >> 20) & 1; const char *opname = opcode_names[opcode]; - return StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", + return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", opname, cond_to_str(cond), bit_s ? "s" : "", rdlo, rdhi, rm, rs); } @@ -599,7 +599,7 @@ std::string ARM_Disasm::DisassembleMUL(Opcode opcode, uint32_t insn) uint8_t bit_s = (insn >> 20) & 1; const char *opname = opcode_names[opcode]; - return StringFromFormat("%s%s%s\tr%d, r%d, r%d", + return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d", opname, cond_to_str(cond), bit_s ? "s" : "", rd, rm, rs); } @@ -609,7 +609,7 @@ std::string ARM_Disasm::DisassembleMRS(uint32_t insn) uint8_t rd = (insn >> 12) & 0xf; uint8_t ps = (insn >> 22) & 1; - return StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); + return Common::StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); } std::string ARM_Disasm::DisassembleMSR(uint32_t insn) @@ -636,13 +636,13 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn) uint8_t rotate = (insn >> 8) & 0xf; uint8_t rotate2 = rotate << 1; uint32_t rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); - return StringFromFormat("msr%s\t%s_%s, #0x%x", + return Common::StringFromFormat("msr%s\t%s_%s, #0x%x", cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rotated_val); } uint8_t rm = insn & 0xf; - return StringFromFormat("msr%s\t%s_%s, r%d", + return Common::StringFromFormat("msr%s\t%s_%s, r%d", cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); } @@ -658,14 +658,14 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn) if (is_reg) { uint8_t rm = insn & 0xf; - return StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm); + return Common::StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm); } uint16_t offset = insn & 0xfff; if (offset == 0) { - return StringFromFormat("pld\t[r%d]", rn); + return Common::StringFromFormat("pld\t[r%d]", rn); } else { - return StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset); + return Common::StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset); } } @@ -674,7 +674,7 @@ std::string ARM_Disasm::DisassembleSWI(uint32_t insn) uint8_t cond = (insn >> 28) & 0xf; uint32_t sysnum = insn & 0x00ffffff; - return StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum); + return Common::StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum); } std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) @@ -685,7 +685,7 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) uint8_t rm = insn & 0xf; const char *opname = opcode_names[opcode]; - return StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); + return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); } Opcode ARM_Disasm::Decode(uint32_t insn) { diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp index d7fc0a042..0f384ad3e 100644 --- a/src/core/arm/disassembler/load_symbol_map.cpp +++ b/src/core/arm/disassembler/load_symbol_map.cpp @@ -6,7 +6,6 @@ #include <vector> #include "common/symbols.h" -#include "common/common_types.h" #include "common/file_util.h" #include "core/arm/disassembler/load_symbol_map.h" @@ -19,7 +18,7 @@ void LoadSymbolMap(std::string filename) { std::ifstream infile(filename); std::string address_str, function_name, line; - u32 size, address; + u32 size; while (std::getline(infile, line)) { std::istringstream iss(line); diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp new file mode 100644 index 000000000..a3ed3e31e --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -0,0 +1,166 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "core/arm/skyeye_common/armcpu.h" +#include "core/arm/skyeye_common/armemu.h" +#include "core/arm/skyeye_common/vfp/vfp.h" + +#include "core/arm/dyncom/arm_dyncom.h" +#include "core/arm/dyncom/arm_dyncom_interpreter.h" + +const static cpu_config_t s_arm11_cpu_info = { + "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE +}; + +ARM_DynCom::ARM_DynCom() : ticks(0) { + state = std::unique_ptr<ARMul_State>(new ARMul_State); + + ARMul_EmulateInit(); + memset(state.get(), 0, sizeof(ARMul_State)); + + ARMul_NewState((ARMul_State*)state.get()); + + state->abort_model = 0; + state->cpu = (cpu_config_t*)&s_arm11_cpu_info; + state->bigendSig = LOW; + + ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); + state->lateabtSig = LOW; + + // Reset the core to initial state + ARMul_CoProInit(state.get()); + ARMul_Reset(state.get()); + state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext + state->Emulate = 3; + + state->pc = state->Reg[15] = 0x00000000; + state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack + state->servaddr = 0xFFFF0000; + state->NirqSig = HIGH; + + VFPInit(state.get()); // Initialize the VFP + + ARMul_EmulateInit(); +} + +ARM_DynCom::~ARM_DynCom() { +} + +/** + * Set the Program Counter to an address + * @param addr Address to set PC to + */ +void ARM_DynCom::SetPC(u32 pc) { + state->pc = state->Reg[15] = pc; +} + +/* + * Get the current Program Counter + * @return Returns current PC + */ +u32 ARM_DynCom::GetPC() const { + return state->Reg[15]; +} + +/** + * Get an ARM register + * @param index Register index (0-15) + * @return Returns the value in the register + */ +u32 ARM_DynCom::GetReg(int index) const { + return state->Reg[index]; +} + +/** + * Set an ARM register + * @param index Register index (0-15) + * @param value Value to set register to + */ +void ARM_DynCom::SetReg(int index, u32 value) { + state->Reg[index] = value; +} + +/** + * Get the current CPSR register + * @return Returns the value of the CPSR register + */ +u32 ARM_DynCom::GetCPSR() const { + return state->Cpsr; +} + +/** + * Set the current CPSR register + * @param cpsr Value to set CPSR to + */ +void ARM_DynCom::SetCPSR(u32 cpsr) { + state->Cpsr = cpsr; +} + +/** + * Returns the number of clock ticks since the last reset + * @return Returns number of clock ticks + */ +u64 ARM_DynCom::GetTicks() const { + return ticks; +} + +/** + * Executes the given number of instructions + * @param num_instructions Number of instructions to executes + */ +void ARM_DynCom::ExecuteInstructions(int num_instructions) { + state->NumInstrsToExecute = num_instructions; + + // Dyncom only breaks on instruction dispatch. This only happens on every instruction when + // executing one instruction at a time. Otherwise, if a block is being executed, more + // instructions may actually be executed than specified. + ticks += InterpreterMainLoop(state.get()); +} + +/** + * Saves the current CPU context + * @param ctx Thread context to save + * @todo Do we need to save Reg[15] and NextInstr? + */ +void ARM_DynCom::SaveContext(ThreadContext& ctx) { + memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); + memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); + + ctx.sp = state->Reg[13]; + ctx.lr = state->Reg[14]; + ctx.pc = state->Reg[15]; + ctx.cpsr = state->Cpsr; + + ctx.fpscr = state->VFP[1]; + ctx.fpexc = state->VFP[2]; + + ctx.reg_15 = state->Reg[15]; + ctx.mode = state->NextInstr; +} + +/** + * Loads a CPU context + * @param ctx Thread context to load + * @param Do we need to load Reg[15] and NextInstr? + */ +void ARM_DynCom::LoadContext(const ThreadContext& ctx) { + memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); + memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); + + state->Reg[13] = ctx.sp; + state->Reg[14] = ctx.lr; + state->pc = ctx.pc; + state->Cpsr = ctx.cpsr; + + state->VFP[1] = ctx.fpscr; + state->VFP[2] = ctx.fpexc; + + state->Reg[15] = ctx.reg_15; + state->NextInstr = ctx.mode; +} + +/// Prepare core for thread reschedule (if needed to correctly handle state) +void ARM_DynCom::PrepareReschedule() { + state->NumInstrsToExecute = 0; +} diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h new file mode 100644 index 000000000..1f8cd3a3a --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -0,0 +1,90 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <memory> + +#include "common/common_types.h" + +#include "core/arm/arm_interface.h" +#include "core/arm/skyeye_common/armdefs.h" + +class ARM_DynCom final : virtual public ARM_Interface { +public: + + ARM_DynCom(); + ~ARM_DynCom(); + + /** + * Set the Program Counter to an address + * @param addr Address to set PC to + */ + void SetPC(u32 pc) override; + + /* + * Get the current Program Counter + * @return Returns current PC + */ + u32 GetPC() const; + + /** + * Get an ARM register + * @param index Register index (0-15) + * @return Returns the value in the register + */ + u32 GetReg(int index) const; + + /** + * Set an ARM register + * @param index Register index (0-15) + * @param value Value to set register to + */ + void SetReg(int index, u32 value) override; + + /** + * Get the current CPSR register + * @return Returns the value of the CPSR register + */ + u32 GetCPSR() const; + + /** + * Set the current CPSR register + * @param cpsr Value to set CPSR to + */ + void SetCPSR(u32 cpsr) override; + + /** + * Returns the number of clock ticks since the last reset + * @return Returns number of clock ticks + */ + u64 GetTicks() const; + + /** + * Saves the current CPU context + * @param ctx Thread context to save + */ + void SaveContext(ThreadContext& ctx) override; + + /** + * Loads a CPU context + * @param ctx Thread context to load + */ + void LoadContext(const ThreadContext& ctx) override; + + /// Prepare core for thread reschedule (if needed to correctly handle state) + void PrepareReschedule() override; + + /** + * Executes the given number of instructions + * @param num_instructions Number of instructions to executes + */ + void ExecuteInstructions(int num_instructions) override; + +private: + + std::unique_ptr<ARMul_State> state; + u64 ticks; + +}; diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp new file mode 100644 index 000000000..5d174a08f --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp @@ -0,0 +1,402 @@ +/* Copyright (C) +* 2012 - Michael.Kang blackfin.kang@gmail.com +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ +/** +* @file arm_dyncom_dec.cpp +* @brief Some common utility for arm decoder +* @author Michael.Kang blackfin.kang@gmail.com +* @version 7849 +* @date 2012-03-15 +*/ + +#include "core/arm/skyeye_common/arm_regformat.h" +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/dyncom/arm_dyncom_dec.h" + +const ISEITEM arm_instruction[] = { + #define VFP_DECODE + #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" + #undef VFP_DECODE + {"srs" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005}, + {"rfe" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a}, + {"bkpt" , 2 , 3 , 20, 31, 0x00000e12, 4, 7, 0x00000007}, + {"blx" , 1 , 3 , 25, 31, 0x0000007d}, + {"cps" , 3 , 6 , 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000}, + {"pld" , 4 , 4 , 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f}, + {"setend" , 2 , 6 , 16, 31, 0x0000f101, 4, 7, 0x00000000}, + {"clrex" , 1 , 6 , 0, 31, 0xf57ff01f}, + {"rev16" , 2 , 6 , 16, 27, 0x000006bf, 4, 11, 0x000000fb}, + {"usad8" , 3 , 6 , 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001}, + {"sxtb" , 2 , 6 , 16, 27, 0x000006af, 4, 7, 0x00000007}, + {"uxtb" , 2 , 6 , 16, 27, 0x000006ef, 4, 7, 0x00000007}, + {"sxth" , 2 , 6 , 16, 27, 0x000006bf, 4, 7, 0x00000007}, + {"sxtb16" , 2 , 6 , 16, 27, 0x0000068f, 4, 7, 0x00000007}, + {"uxth" , 2 , 6 , 16, 27, 0x000006ff, 4, 7, 0x00000007}, + {"uxtb16" , 2 , 6 , 16, 27, 0x000006cf, 4, 7, 0x00000007}, + {"cpy" , 2 , 6 , 20, 27, 0x0000001a, 4, 11, 0x00000000}, + {"uxtab" , 2 , 6 , 20, 27, 0x0000006e, 4, 9, 0x00000007}, + {"ssub8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x0000000f}, + {"shsub8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x0000000f}, + {"ssubaddx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000005}, + {"strex" , 2 , 6 , 20, 27, 0x00000018, 4, 7, 0x00000009}, + {"strexb" , 2 , 7 , 20, 27, 0x0000001c, 4, 7, 0x00000009}, + {"swp" , 2 , 0 , 20, 27, 0x00000010, 4, 7, 0x00000009}, + {"swpb" , 2 , 0 , 20, 27, 0x00000014, 4, 7, 0x00000009}, + {"ssub16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000007}, + {"ssat16" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000003}, + {"shsubaddx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000005}, + {"qsubaddx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000005}, + {"shaddsubx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000003}, + {"shadd8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000009}, + {"shadd16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000001}, + {"sel" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x0000000b}, + {"saddsubx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000003}, + {"sadd8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000009}, + {"sadd16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000001}, + {"shsub16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000007}, + {"umaal" , 2 , 6 , 20, 27, 0x00000004, 4, 7, 0x00000009}, + {"uxtab16" , 2 , 6 , 20, 27, 0x0000006c, 4, 7, 0x00000007}, + {"usubaddx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000005}, + {"usub8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x0000000f}, + {"usub16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000007}, + {"usat16" , 2 , 6 , 20, 27, 0x0000006e, 4, 7, 0x00000003}, + {"usada8" , 2 , 6 , 20, 27, 0x00000078, 4, 7, 0x00000001}, + {"uqsubaddx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000005}, + {"uqsub8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x0000000f}, + {"uqsub16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000007}, + {"uqaddsubx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000003}, + {"uqadd8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000009}, + {"uqadd16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000001}, + {"sxtab" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000007}, + {"uhsubaddx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000005}, + {"uhsub8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x0000000f}, + {"uhsub16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000007}, + {"uhaddsubx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000003}, + {"uhadd8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000009}, + {"uhadd16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000001}, + {"uaddsubx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000003}, + {"uadd8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000009}, + {"uadd16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000001}, + {"sxtah" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000007}, + {"sxtab16" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x00000007}, + {"qadd8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000009}, + {"bxj" , 2 , 5 , 20, 27, 0x00000012, 4, 7, 0x00000002}, + {"clz" , 2 , 3 , 20, 27, 0x00000016, 4, 7, 0x00000001}, + {"uxtah" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x00000007}, + {"bx" , 2 , 2 , 20, 27, 0x00000012, 4, 7, 0x00000001}, + {"rev" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000003}, + {"blx" , 2 , 3 , 20, 27, 0x00000012, 4, 7, 0x00000003}, + {"revsh" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x0000000b}, + {"qadd" , 2 , 4 , 20, 27, 0x00000010, 4, 7, 0x00000005}, + {"qadd16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000001}, + {"qaddsubx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000003}, + {"ldrex" , 2 , 0 , 20, 27, 0x00000019, 4, 7, 0x00000009}, + {"qdadd" , 2 , 4 , 20, 27, 0x00000014, 4, 7, 0x00000005}, + {"qdsub" , 2 , 4 , 20, 27, 0x00000016, 4, 7, 0x00000005}, + {"qsub" , 2 , 4 , 20, 27, 0x00000012, 4, 7, 0x00000005}, + {"ldrexb" , 2 , 7 , 20, 27, 0x0000001d, 4, 7, 0x00000009}, + {"qsub8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x0000000f}, + {"qsub16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000007}, + {"smuad" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001}, + {"smmul" , 4 , 6 , 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001}, + {"smusd" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001}, + {"smlsd" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001}, + {"smlsld" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001}, + {"smmla" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001}, + {"smmls" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001}, + {"smlald" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001}, + {"smlad" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001}, + {"smlaw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000}, + {"smulw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002}, + {"pkhtb" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000005}, + {"pkhbt" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000001}, + {"smul" , 3 , 4 , 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000}, + {"smlalxy" , 3 , 4 , 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000}, +// {"smlal" , 2 , 4 , 21, 27, 0x00000007, 4, 7, 0x00000009}, + {"smla" , 3 , 4 , 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000}, + {"mcrr" , 1 , 6 , 20, 27, 0x000000c4}, + {"mrrc" , 1 , 6 , 20, 27, 0x000000c5}, + {"cmp" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000015}, + {"tst" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000011}, + {"teq" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000013}, + {"cmn" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000017}, + {"smull" , 2 , 0 , 21, 27, 0x00000006, 4, 7, 0x00000009}, + {"umull" , 2 , 0 , 21, 27, 0x00000004, 4, 7, 0x00000009}, + {"umlal" , 2 , 0 , 21, 27, 0x00000005, 4, 7, 0x00000009}, + {"smlal" , 2 , 0 , 21, 27, 0x00000007, 4, 7, 0x00000009}, + {"mul" , 2 , 0 , 21, 27, 0x00000000, 4, 7, 0x00000009}, + {"mla" , 2 , 0 , 21, 27, 0x00000001, 4, 7, 0x00000009}, + {"ssat" , 2 , 6 , 21, 27, 0x00000035, 4, 5, 0x00000001}, + {"usat" , 2 , 6 , 21, 27, 0x00000037, 4, 5, 0x00000001}, + {"mrs" , 4 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000}, + {"msr" , 3 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000}, + {"and" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000000}, + {"bic" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000e}, + {"ldm" , 3 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000}, + {"eor" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000001}, + {"add" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000004}, + {"rsb" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000003}, + {"rsc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000007}, + {"sbc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000006}, + {"adc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000005}, + {"sub" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000002}, + {"orr" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000c}, + {"mvn" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000f}, + {"mov" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000d}, + {"stm" , 2 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000004}, + {"ldm" , 4 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001}, + {"ldrsh" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f}, + {"stm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000}, + {"ldm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001}, + {"ldrsb" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d}, + {"strd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f}, + {"ldrh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b}, + {"strh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b}, + {"ldrd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d}, + {"strt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002}, + {"strbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006}, + {"ldrbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007}, + {"ldrt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003}, + {"mrc" , 3 , 6 , 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001}, + {"mcr" , 3 , 0 , 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001}, + {"msr" , 2 , 0 , 23, 27, 0x00000006, 20, 21, 0x00000002}, + {"ldrb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001}, + {"strb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000}, + {"ldr" , 4 , 0 , 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001}, + {"ldrcond" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001}, + {"str" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000}, + {"cdp" , 2 , 0 , 24, 27, 0x0000000e, 4, 4, 0x00000000}, + {"stc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000000}, + {"ldc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000001}, + {"swi" , 1 , 0 , 24, 27, 0x0000000f}, + {"bbl" , 1 , 0 , 25, 27, 0x00000005}, +}; + +const ISEITEM arm_exclusion_code[] = { + #define VFP_DECODE_EXCLUSION + #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" + #undef VFP_DECODE_EXCLUSION + {"srs" , 0 , 6 , 0}, + {"rfe" , 0 , 6 , 0}, + {"bkpt" , 0 , 3 , 0}, + {"blx" , 0 , 3 , 0}, + {"cps" , 0 , 6 , 0}, + {"pld" , 0 , 4 , 0}, + {"setend" , 0 , 6 , 0}, + {"clrex" , 0 , 6 , 0}, + {"rev16" , 0 , 6 , 0}, + {"usad8" , 0 , 6 , 0}, + {"sxtb" , 0 , 6 , 0}, + {"uxtb" , 0 , 6 , 0}, + {"sxth" , 0 , 6 , 0}, + {"sxtb16" , 0 , 6 , 0}, + {"uxth" , 0 , 6 , 0}, + {"uxtb16" , 0 , 6 , 0}, + {"cpy" , 0 , 6 , 0}, + {"uxtab" , 0 , 6 , 0}, + {"ssub8" , 0 , 6 , 0}, + {"shsub8" , 0 , 6 , 0}, + {"ssubaddx" , 0 , 6 , 0}, + {"strex" , 0 , 6 , 0}, + {"strexb" , 0 , 7 , 0}, + {"swp" , 0 , 0 , 0}, + {"swpb" , 0 , 0 , 0}, + {"ssub16" , 0 , 6 , 0}, + {"ssat16" , 0 , 6 , 0}, + {"shsubaddx" , 0 , 6 , 0}, + {"qsubaddx" , 0 , 6 , 0}, + {"shaddsubx" , 0 , 6 , 0}, + {"shadd8" , 0 , 6 , 0}, + {"shadd16" , 0 , 6 , 0}, + {"sel" , 0 , 6 , 0}, + {"saddsubx" , 0 , 6 , 0}, + {"sadd8" , 0 , 6 , 0}, + {"sadd16" , 0 , 6 , 0}, + {"shsub16" , 0 , 6 , 0}, + {"umaal" , 0 , 6 , 0}, + {"uxtab16" , 0 , 6 , 0}, + {"usubaddx" , 0 , 6 , 0}, + {"usub8" , 0 , 6 , 0}, + {"usub16" , 0 , 6 , 0}, + {"usat16" , 0 , 6 , 0}, + {"usada8" , 0 , 6 , 0}, + {"uqsubaddx" , 0 , 6 , 0}, + {"uqsub8" , 0 , 6 , 0}, + {"uqsub16" , 0 , 6 , 0}, + {"uqaddsubx" , 0 , 6 , 0}, + {"uqadd8" , 0 , 6 , 0}, + {"uqadd16" , 0 , 6 , 0}, + {"sxtab" , 0 , 6 , 0}, + {"uhsubaddx" , 0 , 6 , 0}, + {"uhsub8" , 0 , 6 , 0}, + {"uhsub16" , 0 , 6 , 0}, + {"uhaddsubx" , 0 , 6 , 0}, + {"uhadd8" , 0 , 6 , 0}, + {"uhadd16" , 0 , 6 , 0}, + {"uaddsubx" , 0 , 6 , 0}, + {"uadd8" , 0 , 6 , 0}, + {"uadd16" , 0 , 6 , 0}, + {"sxtah" , 0 , 6 , 0}, + {"sxtab16" , 0 , 6 , 0}, + {"qadd8" , 0 , 6 , 0}, + {"bxj" , 0 , 5 , 0}, + {"clz" , 0 , 3 , 0}, + {"uxtah" , 0 , 6 , 0}, + {"bx" , 0 , 2 , 0}, + {"rev" , 0 , 6 , 0}, + {"blx" , 0 , 3 , 0}, + {"revsh" , 0 , 6 , 0}, + {"qadd" , 0 , 4 , 0}, + {"qadd16" , 0 , 6 , 0}, + {"qaddsubx" , 0 , 6 , 0}, + {"ldrex" , 0 , 0 , 0}, + {"qdadd" , 0 , 4 , 0}, + {"qdsub" , 0 , 4 , 0}, + {"qsub" , 0 , 4 , 0}, + {"ldrexb" , 0 , 7 , 0}, + {"qsub8" , 0 , 6 , 0}, + {"qsub16" , 0 , 6 , 0}, + {"smuad" , 0 , 6 , 0}, + {"smmul" , 0 , 6 , 0}, + {"smusd" , 0 , 6 , 0}, + {"smlsd" , 0 , 6 , 0}, + {"smlsld" , 0 , 6 , 0}, + {"smmla" , 0 , 6 , 0}, + {"smmls" , 0 , 6 , 0}, + {"smlald" , 0 , 6 , 0}, + {"smlad" , 0 , 6 , 0}, + {"smlaw" , 0 , 4 , 0}, + {"smulw" , 0 , 4 , 0}, + {"pkhtb" , 0 , 6 , 0}, + {"pkhbt" , 0 , 6 , 0}, + {"smul" , 0 , 4 , 0}, + {"smlal" , 0 , 4 , 0}, + {"smla" , 0 , 4 , 0}, + {"mcrr" , 0 , 6 , 0}, + {"mrrc" , 0 , 6 , 0}, + {"cmp" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"tst" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"teq" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"cmn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"smull" , 0 , 0 , 0}, + {"umull" , 0 , 0 , 0}, + {"umlal" , 0 , 0 , 0}, + {"smlal" , 0 , 0 , 0}, + {"mul" , 0 , 0 , 0}, + {"mla" , 0 , 0 , 0}, + {"ssat" , 0 , 6 , 0}, + {"usat" , 0 , 6 , 0}, + {"mrs" , 0 , 0 , 0}, + {"msr" , 0 , 0 , 0}, + {"and" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"bic" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"ldm" , 0 , 0 , 0}, + {"eor" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"add" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"rsb" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"rsc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"sbc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"adc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"sub" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"orr" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"mvn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"mov" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, + {"stm" , 0 , 0 , 0}, + {"ldm" , 0 , 0 , 0}, + {"ldrsh" , 0 , 2 , 0}, + {"stm" , 0 , 0 , 0}, + {"ldm" , 0 , 0 , 0}, + {"ldrsb" , 0 , 2 , 0}, + {"strd" , 0 , 4 , 0}, + {"ldrh" , 0 , 0 , 0}, + {"strh" , 0 , 0 , 0}, + {"ldrd" , 0 , 4 , 0}, + {"strt" , 0 , 0 , 0}, + {"strbt" , 0 , 0 , 0}, + {"ldrbt" , 0 , 0 , 0}, + {"ldrt" , 0 , 0 , 0}, + {"mrc" , 0 , 6 , 0}, + {"mcr" , 0 , 0 , 0}, + {"msr" , 0 , 0 , 0}, + {"ldrb" , 0 , 0 , 0}, + {"strb" , 0 , 0 , 0}, + {"ldr" , 0 , 0 , 0}, + {"ldrcond" , 1 , 0 , 28, 31, 0x0000000e}, + {"str" , 0 , 0 , 0}, + {"cdp" , 0 , 0 , 0}, + {"stc" , 0 , 0 , 0}, + {"ldc" , 0 , 0 , 0}, + {"swi" , 0 , 0 , 0}, + {"bbl" , 0 , 0 , 0}, + {"bl_1_thumb", 0, INVALID, 0},/* should be table[-4] */ + {"bl_2_thumb", 0, INVALID, 0}, /* should be located at the end of the table[-3] */ + {"blx_1_thumb", 0, INVALID, 0}, /* should be located at table[-2] */ + {"invalid", 0, INVALID, 0} +}; + +int decode_arm_instr(uint32_t instr, int32_t *idx) +{ + int n = 0; + int base = 0; + int ret = DECODE_FAILURE; + int i = 0; + int instr_slots = sizeof(arm_instruction)/sizeof(ISEITEM); + for (i = 0; i < instr_slots; i++) + { +// ret = DECODE_SUCCESS; + n = arm_instruction[i].attribute_value; + base = 0; + while (n) { + if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) { + /* clrex */ + if (instr != arm_instruction[i].content[base + 2]) { + break; + } + } else if (BITS(arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) { + break; + } + base += 3; + n --; + } + //All conditions is satisfied. + if (n == 0) + ret = DECODE_SUCCESS; + + if (ret == DECODE_SUCCESS) { + n = arm_exclusion_code[i].attribute_value; + if (n != 0) { + base = 0; + while (n) { + if (BITS(arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) { + break; } + base += 3; + n --; + } + //All conditions is satisfied. + if (n == 0) + ret = DECODE_FAILURE; + } + } + + if (ret == DECODE_SUCCESS) { + *idx = i; + return ret; + } + } + return ret; +} + diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h new file mode 100644 index 000000000..19d94f369 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_dec.h @@ -0,0 +1,155 @@ +/* Copyright (C) +* 2012 - Michael.Kang blackfin.kang@gmail.com +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ + +/** +* @file arm_dyncom_dec.h +* @brief Some common utility for arm instruction decoder +* @author Michael.Kang blackfin.kang@gmail.com +* @version 7849 +* @date 2012-03-15 +*/ + +#ifndef __ARM_DYNCOM_DEC__ +#define __ARM_DYNCOM_DEC__ + +#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1)) +#define BIT(n) ((instr >> (n)) & 1) +#define BAD do{printf("meet BAD at %s, instr is %x\n", __FUNCTION__, instr ); /*exit(0);*/}while(0); +#define ptr_N cpu->ptr_N +#define ptr_Z cpu->ptr_Z +#define ptr_C cpu->ptr_C +#define ptr_V cpu->ptr_V +#define ptr_I cpu->ptr_I +#define ptr_T cpu->ptr_T +#define ptr_CPSR cpu->ptr_gpr[16] + +/* for MUL instructions */ +/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */ +#define RDHi ((instr >> 16) & 0xF) +/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */ +#define RDLo ((instr >> 12) & 0xF) +/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */ +#define MUL_RD ((instr >> 16) & 0xF) +/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */ +#define MUL_RN ((instr >> 12) & 0xF) +/*xxxx xxxx xxxx xxxx xxxx 1111 xxxx xxxx */ +#define RS ((instr >> 8) & 0xF) + +/*xxxx xxxx xxxx xxxx 1111 xxxx xxxx xxxx */ +#define RD ((instr >> 12) & 0xF) +/*xxxx xxxx xxxx 1111 xxxx xxxx xxxx xxxx */ +#define RN ((instr >> 16) & 0xF) +/*xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 */ +#define RM (instr & 0xF) +#define BIT(n) ((instr >> (n)) & 1) +#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1)) + +/* CP15 registers */ +#define OPCODE_1 BITS(21, 23) +#define CRn BITS(16, 19) +#define CRm BITS(0, 3) +#define OPCODE_2 BITS(5, 7) + +/*xxxx xx1x xxxx xxxx xxxx xxxx xxxx xxxx */ +#define I BIT(25) +/*xxxx xxxx xxx1 xxxx xxxx xxxx xxxx xxxx */ +#define S BIT(20) + +#define SHIFT BITS(5,6) +#define SHIFT_IMM BITS(7,11) +#define IMMH BITS(8,11) +#define IMML BITS(0,3) + +#define LSPBIT BIT(24) +#define LSUBIT BIT(23) +#define LSBBIT BIT(22) +#define LSWBIT BIT(21) +#define LSLBIT BIT(20) +#define LSSHBITS BITS(5,6) +#define OFFSET12 BITS(0,11) +#define SBIT BIT(20) +#define DESTReg (BITS (12, 15)) + +/* they are in unused state, give a corrent value when using */ +#define IS_V5E 0 +#define IS_V5 0 +#define IS_V6 0 +#define LHSReg 0 + +/* temp define the using the pc reg need implement a flow */ +#define STORE_CHECK_RD_PC ADD(R(RD), CONST(INSTR_SIZE * 2)) + +#define OPERAND operand(cpu,instr,bb,NULL) +#define SCO_OPERAND(sco) operand(cpu,instr,bb,sco) +#define BOPERAND boperand(instr) + +#define CHECK_RN_PC (RN==15? ADD(AND(R(RN), CONST(~0x1)), CONST(INSTR_SIZE * 2)):R(RN)) +#define CHECK_RN_PC_WA (RN==15? ADD(AND(R(RN), CONST(~0x3)), CONST(INSTR_SIZE * 2)):R(RN)) + +#define GET_USER_MODE() (OR(ICMP_EQ(R(MODE_REG), CONST(USER32MODE)), ICMP_EQ(R(MODE_REG), CONST(SYSTEM32MODE)))) + +int decode_arm_instr(uint32_t instr, int32_t *idx); + +enum DECODE_STATUS { + DECODE_SUCCESS, + DECODE_FAILURE +}; + +struct instruction_set_encoding_item { + const char *name; + int attribute_value; + int version; + u32 content[21]; +}; + +typedef struct instruction_set_encoding_item ISEITEM; + +#define RECORD_WB(value, flag) {cpu->dyncom_engine->wb_value = value;cpu->dyncom_engine->wb_flag = flag;} +#define INIT_WB(wb_value, wb_flag) RECORD_WB(wb_value, wb_flag) + +#define EXECUTE_WB(base_reg) {if(cpu->dyncom_engine->wb_flag) \ + LET(base_reg, cpu->dyncom_engine->wb_value);} +inline int get_reg_count(uint32_t instr){ + int i = BITS(0,15); + int count = 0; + while(i){ + if(i & 1) + count ++; + i = i >> 1; + } + return count; +} + +enum ARMVER { + INVALID = 0, + ARMALL, + ARMV4, + ARMV4T, + ARMV5T, + ARMV5TE, + ARMV5TEJ, + ARMV6, + ARM1176JZF_S, + ARMVFP2, + ARMVFP3 +}; + +//extern const INSTRACT arm_instruction_action[]; +extern const ISEITEM arm_instruction[]; + +#endif diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp new file mode 100644 index 000000000..f899e2e8a --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -0,0 +1,6564 @@ +/* Copyright (C) +* 2012 - Michael.Kang blackfin.kang@gmail.com +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ +/** +* @file arm_dyncom_interpreter.cpp +* @brief The fast interpreter for arm +* @author Michael.Kang blackfin.kang@gmail.com +* @version 7849 +* @date 2012-03-15 +*/ + +#define CITRA_IGNORE_EXIT(x) + +#include <algorithm> +#include <map> +#include <stdio.h> +#include <assert.h> +#include <cstdio> +#include <vector> + +using namespace std; + +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/armmmu.h" +#include "arm_dyncom_thumb.h" +#include "arm_dyncom_run.h" +#include "core/arm/skyeye_common/vfp/vfp.h" +/* shenoubang 2012-6-14 */ +#ifdef __WIN32__ +#include "bank_defs.h" +#endif + +#include "core/mem_map.h" +#include "core/hle/hle.h" + +enum { + COND = (1 << 0), + NON_BRANCH = (1 << 1), + DIRECT_BRANCH = (1 << 2), + INDIRECT_BRANCH = (1 << 3), + CALL = (1 << 4), + RET = (1 << 5), + END_OF_PAGE = (1 << 6), + THUMB = (1 << 7) +}; + +#define USER_MODE_OPT 1 +#define HYBRID_MODE 0 // Enable for JIT mode + +#define THRESHOLD 1000 +#define DURATION 500 +//#define PRINT_PROFILE_INFO + +#define CHECK_RS if(RS == 15) rs += 8 +#define CHECK_RM if(RM == 15) rm += 8 + +//#define BITS(s, a, b) (((s) >> (a)) & ((1 << (1 + (b) - (a))) - 1)) +#undef BITS +#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) +#define BIT(s, n) ((s >> (n)) & 1) +#define RM BITS(sht_oper, 0, 3) +#define RS BITS(sht_oper, 8, 11) + +#define glue(x, y) x ## y +#define DPO(s) glue(DataProcessingOperands, s) +#define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i)) +#define ROTATE_LEFT(n, i, l) ((n >> (l - i)) | (n << i)) +#define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32) +#define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32) + +//#define rotr(x,n) ((((x)>>(n))&((1<<(sizeof(x) * 8)-1))|(x<<(sizeof(x)*8-n)))) +//#define rotl(x,n) ((((x)<<(n))&(-(1<<(n))))|(((x)>>(sizeof(x)*8-n))&((1<<(n))-1))) +#define rotr(x,n) ( (x >> n) | ((x & ((1 << (n + 1)) - 1)) << (32 - n)) ) + +extern void switch_mode(arm_core_t *core, uint32_t mode); +//extern bool InAPrivilegedMode(arm_core_t *core); + +typedef arm_core_t arm_processor; +typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper); + +/* exclusive memory access */ +static int exclusive_detect(ARMul_State* state, ARMword addr){ + int i; + #if 0 + for(i = 0; i < 128; i++){ + if(state->exclusive_tag_array[i] == addr) + return 0; + } + #endif + if(state->exclusive_tag == addr) + return 0; + else + return -1; +} + +static void add_exclusive_addr(ARMul_State* state, ARMword addr){ + int i; + #if 0 + for(i = 0; i < 128; i++){ + if(state->exclusive_tag_array[i] == 0xffffffff){ + state->exclusive_tag_array[i] = addr; + //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr); + return; + } + } + DEBUG_LOG(ARM11, "In %s ,can not monitor the addr, out of array\n", __FUNCTION__); + #endif + state->exclusive_tag = addr; + return; +} + +static void remove_exclusive(ARMul_State* state, ARMword addr){ + #if 0 + int i; + for(i = 0; i < 128; i++){ + if(state->exclusive_tag_array[i] == addr){ + state->exclusive_tag_array[i] = 0xffffffff; + //DEBUG_LOG(ARM11, "In %s, remove addr 0x%x\n", __func__, addr); + return; + } + } + #endif + state->exclusive_tag = 0xFFFFFFFF; +} + + +unsigned int DPO(Immediate)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + unsigned int immed_8 = BITS(sht_oper, 0, 7); + unsigned int rotate_imm = BITS(sht_oper, 8, 11); +// DEBUG_LOG(ARM11, "immed_8 is %x\n", immed_8); +// DEBUG_LOG(ARM11, "rotate_imm is %x\n", rotate_imm); + unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);//ROTATE_RIGHT_32(immed_8, rotate_imm * 2); +// DEBUG_LOG(ARM11, "shifter_operand : %x\n", shifter_operand); + /* set c flag */ + if (rotate_imm == 0) + cpu->shifter_carry_out = cpu->CFlag; + else + cpu->shifter_carry_out = BIT(shifter_operand, 31); + return shifter_operand; +} + +unsigned int DPO(Register)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + unsigned int rm = CHECK_READ_REG15(cpu, RM); + //if (RM == 15) rm += 8; + unsigned int shifter_operand = rm; + cpu->shifter_carry_out = cpu->CFlag; + return shifter_operand; +} + +unsigned int DPO(LogicalShiftLeftByImmediate)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + int shift_imm = BITS(sht_oper, 7, 11); + unsigned int rm = CHECK_READ_REG15(cpu, RM); + //if (RM == 15) rm += 8; + unsigned int shifter_operand; + if (shift_imm == 0) { + shifter_operand = rm; + cpu->shifter_carry_out = cpu->CFlag; + } else { + shifter_operand = rm << shift_imm; + cpu->shifter_carry_out = BIT(rm, 32 - shift_imm); + } + return shifter_operand; +} + +unsigned int DPO(LogicalShiftLeftByRegister)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + int shifter_operand; + unsigned int rm = CHECK_READ_REG15(cpu, RM); + unsigned int rs = CHECK_READ_REG15(cpu, RS); + //if (RM == 15) rm += 8; + //if (RS == 15) rs += 8; + if (BITS(rs, 0, 7) == 0) { + shifter_operand = rm; + cpu->shifter_carry_out = cpu->CFlag; + } else if (BITS(rs, 0, 7) < 32) { + shifter_operand = rm << BITS(rs, 0, 7); + cpu->shifter_carry_out = BIT(rm, 32 - BITS(rs, 0, 7)); + } else if (BITS(rs, 0, 7) == 32) { + shifter_operand = 0; + cpu->shifter_carry_out = BIT(rm, 0); + } else { + shifter_operand = 0; + cpu->shifter_carry_out = 0; + } + return shifter_operand; +} + +unsigned int DPO(LogicalShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + //unsigned int rm = cpu->Reg[RM]; + unsigned int rm = CHECK_READ_REG15(cpu, RM); + //if (RM == 15) rm += 8; + unsigned int shifter_operand; + int shift_imm = BITS(sht_oper, 7, 11); + if (shift_imm == 0) { + shifter_operand = 0; + cpu->shifter_carry_out = BIT(rm, 31); + } else { + shifter_operand = rm >> shift_imm; + cpu->shifter_carry_out = BIT(rm, shift_imm - 1); + } + return shifter_operand; +} + +unsigned int DPO(LogicalShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + unsigned int rs = CHECK_READ_REG15(cpu, RS); + unsigned int rm = CHECK_READ_REG15(cpu, RM); + //if (RS == 15) rs += 8; + //if (RM == 15) rm += 8; + unsigned int shifter_operand; + if (BITS(rs, 0, 7) == 0) { + shifter_operand = rm; + cpu->shifter_carry_out = cpu->CFlag; + } else if (BITS(rs, 0, 7) < 32) { + shifter_operand = rm >> BITS(rs, 0, 7); + cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1); + } else if (BITS(rs, 0, 7) == 32) { + shifter_operand = 0; + cpu->shifter_carry_out = BIT(rm, 31); + } else { + shifter_operand = 0; + cpu->shifter_carry_out = 0; + } + return shifter_operand; +} + +unsigned int DPO(ArithmeticShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + //unsigned int rm = cpu->Reg[RM]; + unsigned int rm = CHECK_READ_REG15(cpu, RM); + //if (RM == 15) rm += 8; + unsigned int shifter_operand; + int shift_imm = BITS(sht_oper, 7, 11); + if (shift_imm == 0) { + if (BIT(rm, 31)) { + shifter_operand = 0; + cpu->shifter_carry_out = BIT(rm, 31); + } else { + shifter_operand = 0xFFFFFFFF; + cpu->shifter_carry_out = BIT(rm, 31); + } + } else { + shifter_operand = static_cast<int>(rm) >> shift_imm; + cpu->shifter_carry_out = BIT(rm, shift_imm - 1); + } + return shifter_operand; +} + +unsigned int DPO(ArithmeticShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + //unsigned int rs = cpu->Reg[RS]; + unsigned int rs = CHECK_READ_REG15(cpu, RS); + //unsigned int rm = cpu->Reg[RM]; + unsigned int rm = CHECK_READ_REG15(cpu, RM); + //if (RS == 15) rs += 8; + //if (RM == 15) rm += 8; + unsigned int shifter_operand; + if (BITS(rs, 0, 7) == 0) { + shifter_operand = rm; + cpu->shifter_carry_out = cpu->CFlag; + } else if (BITS(rs, 0, 7) < 32) { + shifter_operand = static_cast<int>(rm) >> BITS(rs, 0, 7); + cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1); + } else { + if (BIT(rm, 31) == 0) { + shifter_operand = 0; + } else + shifter_operand = 0xffffffff; + cpu->shifter_carry_out = BIT(rm, 31); + } + return shifter_operand; +} + +unsigned int DPO(RotateRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + unsigned int shifter_operand; + //unsigned int rm = cpu->Reg[RM]; + unsigned int rm = CHECK_READ_REG15(cpu, RM); + //if (RM == 15) rm += 8; + int shift_imm = BITS(sht_oper, 7, 11); + if (shift_imm == 0) { + shifter_operand = (cpu->CFlag << 31) | + (rm >> 1); + cpu->shifter_carry_out = BIT(rm, 0); + } else { + shifter_operand = ROTATE_RIGHT_32(rm, shift_imm); + cpu->shifter_carry_out = BIT(rm, shift_imm - 1); + } + return shifter_operand; +} + +unsigned int DPO(RotateRightByRegister)(arm_processor *cpu, unsigned int sht_oper) +{ +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + unsigned int rm = CHECK_READ_REG15(cpu, RM); + //if (RM == 15) rm += 8; + unsigned int rs = CHECK_READ_REG15(cpu, RS); + //if (RS == 15) rs += 8; + unsigned int shifter_operand; + if (BITS(rs, 0, 7) == 0) { + shifter_operand = rm; + cpu->shifter_carry_out = cpu->CFlag; + } else if (BITS(rs, 0, 4) == 0) { + shifter_operand = rm; + cpu->shifter_carry_out = BIT(rm, 31); + } else { + shifter_operand = ROTATE_RIGHT_32(rm, BITS(rs, 0, 4)); + cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 4) - 1); + } + #if 0 + if (cpu->icounter >= 20371544) { + DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + DEBUG_LOG(ARM11, "RM:%d\nRS:%d\n", RM, RS); + DEBUG_LOG(ARM11, "rm:0x%08x\nrs:0x%08x\n", cpu->Reg[RM], cpu->Reg[RS]); + } + #endif + return shifter_operand; +} + +//typedef unsigned int (*get_addr_fp_t)(arm_processor *cpu); +typedef struct _MiscImmeData { + unsigned int U; + unsigned int Rn; + unsigned int offset_8; +} MiscLSData; + +typedef struct _MiscRegData { + unsigned int U; + unsigned int Rn; + unsigned int Rm; +} MiscRegData; + +typedef struct _MiscImmePreIdx { + unsigned int offset_8; + unsigned int U; + unsigned int Rn; +} MiscImmePreIdx; + +typedef struct _MiscRegPreIdx { + unsigned int U; + unsigned int Rn; + unsigned int Rm; +} MiscRegPreIdx; + +typedef struct _MiscImmePstIdx { + unsigned int offset_8; + unsigned int U; + unsigned int Rn; +} MIscImmePstIdx; + +typedef struct _MiscRegPstIdx { + unsigned int Rn; + unsigned int Rm; + unsigned int U; +} MiscRegPstIdx; + +typedef struct _LSWordorUnsignedByte { +} LDnST; + +#if USER_MODE_OPT +static inline fault_t interpreter_read_memory(addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size){ + switch(size) { + case 8: + value = Memory::Read8(virt_addr); + break; + case 16: + value = Memory::Read16(virt_addr); + break; + case 32: + value = Memory::Read32(virt_addr); + break; + } + return NO_FAULT; +} + +//static inline void interpreter_write_memory(void *mem_ptr, uint32_t offset, uint32_t value, int size) +static inline fault_t interpreter_write_memory(addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size) +{ + switch(size) { + case 8: + Memory::Write8(virt_addr, value & 0xff); + break; + case 16: + Memory::Write16(virt_addr, value & 0xffff); + break; + case 32: + Memory::Write32(virt_addr, value); + break; + } + return NO_FAULT; +} + +static inline fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw){ + *phys_addr = virt_addr; + return NO_FAULT; +} + +#else +fault_t interpreter_read_memory(cpu_t *cpu, addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size); +fault_t interpreter_write_memory(cpu_t *cpu, addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size); +fault_t interpreter_fetch(cpu_t *cpu, addr_t virt_addr, uint32_t &value, uint32_t size); +fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw, tlb_type_t access_type = DATA_TLB); +#endif + +typedef fault_t (*get_addr_fp_t)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw); + +typedef struct _ldst_inst { + unsigned int inst; + get_addr_fp_t get_addr; +} ldst_inst; +#define DEBUG_MSG DEBUG_LOG(ARM11, "in %s %d\n", __FUNCTION__, __LINE__); \ + DEBUG_LOG(ARM11, "inst is %x\n", inst); \ + CITRA_IGNORE_EXIT(0) + +int CondPassed(arm_processor *cpu, unsigned int cond); +#define LnSWoUB(s) glue(LnSWoUB, s) +#define MLnS(s) glue(MLnS, s) +#define LdnStM(s) glue(LdnStM, s) + +#define W_BIT BIT(inst, 21) +#define U_BIT BIT(inst, 23) +#define I_BIT BIT(inst, 25) +#define P_BIT BIT(inst, 24) +#define OFFSET_12 BITS(inst, 0, 11) +fault_t LnSWoUB(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + unsigned int Rn = BITS(inst, 16, 19); + unsigned int addr; + fault_t fault; + if (U_BIT) { + addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12; + } else { + addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12; + } + //if (Rn == 15) rn += 8; + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + return fault; +// return addr; +} + +fault_t LnSWoUB(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + //if (Rm == 15) rm += 8; + unsigned int addr; + if (U_BIT) { + addr = rn + rm; + } else { + addr = rn - rm; + } + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + return fault; +} + +fault_t LnSWoUB(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) addr += 8; + + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if (fault) return fault; + + if (U_BIT) { + cpu->Reg[Rn] += OFFSET_12; + } else { + cpu->Reg[Rn] -= OFFSET_12; + } + return fault; +} + +fault_t LnSWoUB(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int addr; + if (U_BIT) { + addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12; + } else { + addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12; + } + #if 0 + if (Rn == 15) { + addr += 8; + } + #endif + + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31))) { + cpu->Reg[Rn] = addr; + } + return fault; +} + +fault_t MLnS(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int addr; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + //if (Rn == 15) rn += 8; + //if (Rm == 15) rm += 8; + if (U_BIT) { + addr = rn + rm; + } else + addr = rn - rm; + if(BIT(inst, 20)){ /* L BIT */ + } + if(BIT(inst, 6)){ /* Sign Bit */ + } + if(BIT(inst, 5)){ /* Half Bit */ + } + + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31))) { + cpu->Reg[Rn] = addr; + } + return fault; +} + +fault_t LnSWoUB(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + //if (Rm == 15) rm += 8; + unsigned int addr; + if (U_BIT) { + addr = rn + rm; + } else { + addr = rn - rm; + } + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if(fault) + return fault; + if (CondPassed(cpu, BITS(inst, 28, 31))) { + cpu->Reg[Rn] = addr; + } + return fault; +} +fault_t LnSWoUB(ScaledRegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int shift = BITS(inst, 5, 6); + unsigned int shift_imm = BITS(inst, 7, 11); + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int index; + unsigned int addr; + + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + //if (Rm == 15) rm += 8; + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + switch (shift) { + case 0: + //DEBUG_MSG; + index = rm << shift_imm; + break; + case 1: +// DEBUG_MSG; + if (shift_imm == 0) { + index = 0; + } else { + index = rm >> shift_imm; + } + break; + case 2: + DEBUG_MSG; + break; + case 3: + DEBUG_MSG; + break; + } + if (U_BIT) { + addr = rn + index; + } else + addr = rn - index; + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if(fault) + return fault; + if (CondPassed(cpu, BITS(inst, 28, 31))) { + cpu->Reg[Rn] = addr; + } + + return fault; +} + +fault_t LnSWoUB(ScaledRegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int shift = BITS(inst, 5, 6); + unsigned int shift_imm = BITS(inst, 7, 11); + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int index; + unsigned int addr; + + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + //if (Rm == 15) rm += 8; + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + addr = rn; + switch (shift) { + case 0: + //DEBUG_MSG; + index = rm << shift_imm; + break; + case 1: +// DEBUG_MSG; + if (shift_imm == 0) { + index = 0; + } else { + index = rm >> shift_imm; + } + break; + case 2: + DEBUG_MSG; + break; + case 3: + DEBUG_MSG; + break; + } + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if(fault) + return fault; + if (CondPassed(cpu, BITS(inst, 28, 31))) { + if (U_BIT) + cpu->Reg[Rn] += index; + else + cpu->Reg[Rn] -= index; + } + + return fault; +} + +fault_t LnSWoUB(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + + unsigned int addr = rn; + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31))) { + if (U_BIT) { + cpu->Reg[Rn] += rm; + } else { + cpu->Reg[Rn] -= rm; + } + } + return fault; +} + +fault_t MLnS(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int immedL = BITS(inst, 0, 3); + unsigned int immedH = BITS(inst, 8, 11); + + unsigned int Rn = BITS(inst, 16, 19); + unsigned int addr; + + unsigned int offset_8 = (immedH << 4) | immedL; + if (U_BIT) { + addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; + } else + addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; + #if 0 + if (Rn == 15) { + addr += 8; + } + #endif + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + return fault; +} + +fault_t MLnS(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int addr; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + //if (Rn == 15) rn += 8; + //if (Rm == 15) rm += 8; + if (U_BIT) { + addr = rn + rm; + } else + addr = rn - rm; + if(BIT(inst, 20)){ /* L BIT */ + } + if(BIT(inst, 6)){ /* Sign Bit */ + } + if(BIT(inst, 5)){ /* Half Bit */ + } + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + return fault; +} + +fault_t MLnS(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int immedH = BITS(inst, 8, 11); + unsigned int immedL = BITS(inst, 0, 3); + unsigned int addr; + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + +// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); + unsigned int offset_8 = (immedH << 4) | immedL; + if (U_BIT) { + addr = rn + offset_8; + } else + addr = rn - offset_8; + + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31))) { + cpu->Reg[Rn] = addr; + } + return fault; +} + +fault_t MLnS(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int immedH = BITS(inst, 8, 11); + unsigned int immedL = BITS(inst, 0, 3); + unsigned int addr; + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + addr = rn; + + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31))) { + unsigned int offset_8 = (immedH << 4) | immedL; + if (U_BIT) { + rn += offset_8; + } else { + rn -= offset_8; + } + cpu->Reg[Rn] = rn; + } + + return fault; +} +fault_t MLnS(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + + unsigned int addr = rn; + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31))) { + if (U_BIT) { + cpu->Reg[Rn] += rm; + } else { + cpu->Reg[Rn] -= rm; + } + } + return fault; +} + +fault_t LdnStM(DecrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int i = BITS(inst, 0, 15); + int count = 0; + while(i) { + if(i & 1) count ++; + i = i >> 1; + } + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + unsigned int start_addr = rn - count * 4; + unsigned int end_addr = rn - 4; + + fault = check_address_validity(cpu, end_addr, &phys_addr, rw); + virt_addr = end_addr; + if (fault) return fault; + + fault = check_address_validity(cpu, start_addr, &phys_addr, rw); + virt_addr = start_addr; + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { + cpu->Reg[Rn] -= count * 4; + } + + return fault; +} + +fault_t LdnStM(IncrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int i = BITS(inst, 0, 15); + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + int count = 0; + while(i) { + if(i & 1) count ++; + i = i >> 1; + } + + unsigned int start_addr = rn + 4; + unsigned int end_addr = rn + count * 4; + + fault = check_address_validity(cpu, end_addr, &phys_addr, rw); + virt_addr = end_addr; + if (fault) return fault; + + fault = check_address_validity(cpu, start_addr, &phys_addr, rw); + virt_addr = start_addr; + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { + cpu->Reg[Rn] += count * 4; + } + return fault; +} + +fault_t LdnStM(IncrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int i = BITS(inst, 0, 15); + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + int count = 0; + while(i) { + if(i & 1) count ++; + i = i >> 1; + } + //if (Rn == 15) rn += 8; + unsigned int start_addr = rn; + unsigned int end_addr = rn + count * 4 - 4; + + fault = check_address_validity(cpu, end_addr, &phys_addr, rw); + virt_addr = end_addr; + if (fault) return fault; + + fault = check_address_validity(cpu, start_addr, &phys_addr, rw); + virt_addr = start_addr; + if (fault) return fault; + + if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { + cpu->Reg[Rn] += count * 4; + } + return fault; +} + +fault_t LdnStM(DecrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int i = BITS(inst, 0, 15); + int count = 0; + while(i) { + if(i & 1) count ++; + i = i >> 1; + } + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + unsigned int start_addr = rn - count * 4 + 4; + unsigned int end_addr = rn; + + fault = check_address_validity(cpu, end_addr, &phys_addr, rw); + virt_addr = end_addr; + if (fault) return fault; + + fault = check_address_validity(cpu, start_addr, &phys_addr, rw); + if (fault) return fault; + virt_addr = start_addr; + + if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) { + cpu->Reg[Rn] -= count * 4; + } + return fault; +} + +fault_t LnSWoUB(ScaledRegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) +{ + fault_t fault; + unsigned int shift = BITS(inst, 5, 6); + unsigned int shift_imm = BITS(inst, 7, 11); + unsigned int Rn = BITS(inst, 16, 19); + unsigned int Rm = BITS(inst, 0, 3); + unsigned int index; + unsigned int addr; + + unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); + //if (Rm == 15) rm += 8; + unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); + //if (Rn == 15) rn += 8; + switch (shift) { + case 0: + //DEBUG_MSG; + index = rm << shift_imm; + break; + case 1: +// DEBUG_MSG; + if (shift_imm == 0) { + index = 0; + } else { + index = rm >> shift_imm; + } + break; + case 2: + if (shift_imm == 0){ /* ASR #32 */ + if (rm >> 31) + index = 0xFFFFFFFF; + else + index = 0; + } + else { + index = static_cast<int>(rm) >> shift_imm; + } + break; + case 3: + DEBUG_MSG; + break; + } + if (U_BIT) { + addr = rn + index; + } else + addr = rn - index; + virt_addr = addr; + fault = check_address_validity(cpu, addr, &phys_addr, rw); + return fault; +} + +#define ISNEG(n) (n < 0) +#define ISPOS(n) (n >= 0) + +//enum { +// COND = (1 << 0), +// NON_BRANCH = (1 << 1), +// DIRECT_BRANCH = (1 << 2), +// INDIRECT_BRANCH = (1 << 3), +// CALL = (1 << 4), +// RET = (1 << 5), +// END_OF_PAGE = (1 << 6), +// THUMB = (1 << 7) +//}; + +typedef struct _arm_inst { + unsigned int idx; + unsigned int cond; + int br; + int load_r15; + char component[0]; +} arm_inst; + +typedef struct _adc_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} adc_inst; + +typedef struct _add_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} add_inst; + +typedef struct _orr_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} orr_inst; + +typedef struct _and_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} and_inst; + +typedef struct _eor_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} eor_inst; + +typedef struct _bbl_inst { + unsigned int L; + int signed_immed_24; + unsigned int next_addr; + unsigned int jmp_addr; +} bbl_inst; + +typedef struct _bx_inst { + unsigned int Rm; +} bx_inst; + +typedef struct _blx_inst { + union { + int32_t signed_immed_24; + uint32_t Rm; + } val; + unsigned int inst; +} blx_inst; + +typedef struct _clz_inst { + unsigned int Rm; + unsigned int Rd; +} clz_inst; + +typedef struct _cps_inst { + unsigned int imod0; + unsigned int imod1; + unsigned int mmod; + unsigned int A, I, F; + unsigned int mode; +} cps_inst; + +typedef struct _clrex_inst { +} clrex_inst; + +typedef struct _cpy_inst { + unsigned int Rm; + unsigned int Rd; +} cpy_inst; + +typedef struct _bic_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} bic_inst; + +typedef struct _sub_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} sub_inst; + +typedef struct _tst_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} tst_inst; + +typedef struct _cmn_inst { + unsigned int I; + //unsigned int S; + unsigned int Rn; + //unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} cmn_inst; + +typedef struct _teq_inst { + unsigned int I; + unsigned int Rn; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} teq_inst; + +typedef struct _stm_inst { + unsigned int inst; +} stm_inst; + +struct bkpt_inst { +}; + +struct blx1_inst { + unsigned int addr; +}; + +struct blx2_inst { + unsigned int Rm; +}; + +typedef struct _stc_inst { +} stc_inst; + +typedef struct _ldc_inst { +} ldc_inst; + +typedef struct _swi_inst { + unsigned int num; +} swi_inst; + +typedef struct _cmp_inst { + unsigned int I; + unsigned int Rn; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} cmp_inst; + +typedef struct _mov_inst { + unsigned int I; + unsigned int S; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} mov_inst; + +typedef struct _mvn_inst { + unsigned int I; + unsigned int S; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} mvn_inst; + +typedef struct _rev_inst { + unsigned int Rd; + unsigned int Rm; +} rev_inst; + +typedef struct _rsb_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} rsb_inst; + +typedef struct _rsc_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} rsc_inst; + +typedef struct _sbc_inst { + unsigned int I; + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int shifter_operand; + shtop_fp_t shtop_func; +} sbc_inst; + +typedef struct _mul_inst { + unsigned int S; + unsigned int Rd; + unsigned int Rs; + unsigned int Rm; +} mul_inst; + +typedef struct _smul_inst { + unsigned int Rd; + unsigned int Rs; + unsigned int Rm; + unsigned int x; + unsigned int y; +} smul_inst; + +typedef struct _umull_inst { + unsigned int S; + unsigned int RdHi; + unsigned int RdLo; + unsigned int Rs; + unsigned int Rm; +} umull_inst; +typedef struct _smlad_inst { + unsigned int m; + unsigned int Rm; + unsigned int Rd; + unsigned int Ra; + unsigned int Rn; +} smlad_inst; + +typedef struct _smla_inst { + unsigned int x; + unsigned int y; + unsigned int Rm; + unsigned int Rd; + unsigned int Rs; + unsigned int Rn; +} smla_inst; + +typedef struct _umlal_inst { + unsigned int S; + unsigned int Rm; + unsigned int Rs; + unsigned int RdHi; + unsigned int RdLo; +} umlal_inst; + +typedef struct _smlal_inst { + unsigned int S; + unsigned int Rm; + unsigned int Rs; + unsigned int RdHi; + unsigned int RdLo; +} smlal_inst; + +typedef struct _mla_inst { + unsigned int S; + unsigned int Rn; + unsigned int Rd; + unsigned int Rs; + unsigned int Rm; +} mla_inst; + +typedef struct _mrc_inst { + unsigned int opcode_1; + unsigned int opcode_2; + unsigned int cp_num; + unsigned int crn; + unsigned int crm; + unsigned int Rd; + unsigned int inst; +} mrc_inst; + +typedef struct _mcr_inst { + unsigned int opcode_1; + unsigned int opcode_2; + unsigned int cp_num; + unsigned int crn; + unsigned int crm; + unsigned int Rd; + unsigned int inst; +} mcr_inst; + +typedef struct _mrs_inst { + unsigned int R; + unsigned int Rd; +} mrs_inst; + +typedef struct _msr_inst { + unsigned int field_mask; + unsigned int R; + unsigned int inst; +} msr_inst; + +typedef struct _pld_inst { +} pld_inst; + +typedef struct _sxtb_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int rotate; +} sxtb_inst; + +typedef struct _sxtab_inst { + unsigned int Rd; + unsigned int Rn; + unsigned int Rm; + unsigned rotate; +} sxtab_inst; + +typedef struct _sxtah_inst { + unsigned int Rd; + unsigned int Rn; + unsigned int Rm; + unsigned int rotate; +} sxtah_inst; + +typedef struct _sxth_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int rotate; +} sxth_inst; + +typedef struct _uxtab_inst { + unsigned int Rn; + unsigned int Rd; + unsigned int rotate; + unsigned int Rm; +} uxtab_inst; + +typedef struct _uxtah_inst { + unsigned int Rn; + unsigned int Rd; + unsigned int rotate; + unsigned int Rm; +} uxtah_inst; + +typedef struct _uxth_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int rotate; +} uxth_inst; + +typedef struct _cdp_inst { + unsigned int opcode_1; + unsigned int CRn; + unsigned int CRd; + unsigned int cp_num; + unsigned int opcode_2; + unsigned int CRm; + uint32 inst; +}cdp_inst; + +typedef struct _uxtb_inst { + unsigned int Rd; + unsigned int Rm; + unsigned int rotate; +} uxtb_inst; + +typedef struct _swp_inst { + unsigned int Rn; + unsigned int Rd; + unsigned int Rm; +} swp_inst; + +typedef struct _b_2_thumb { + unsigned int imm; +}b_2_thumb; +typedef struct _b_cond_thumb { + unsigned int imm; + unsigned int cond; +}b_cond_thumb; + +typedef struct _bl_1_thumb { + unsigned int imm; +}bl_1_thumb; +typedef struct _bl_2_thumb { + unsigned int imm; +}bl_2_thumb; +typedef struct _blx_1_thumb { + unsigned int imm; + unsigned int instr; +}blx_1_thumb; + +typedef arm_inst * ARM_INST_PTR; + +#define CACHE_BUFFER_SIZE (64 * 1024 * 2000) +char inst_buf[CACHE_BUFFER_SIZE]; +int top = 0; +inline void *AllocBuffer(unsigned int size) +{ + int start = top; + top += size; + if (top > CACHE_BUFFER_SIZE) { + DEBUG_LOG(ARM11, "inst_buf is full\n"); + CITRA_IGNORE_EXIT(-1); + } + return (void *)&inst_buf[start]; +} + +int CondPassed(arm_processor *cpu, unsigned int cond) +{ + #define NFLAG cpu->NFlag + #define ZFLAG cpu->ZFlag + #define CFLAG cpu->CFlag + #define VFLAG cpu->VFlag + int temp; + switch (cond) { + case 0x0: + temp = ZFLAG; + break; + case 0x1: /* NE */ + temp = !ZFLAG; + break; + case 0x6: /* VS */ + temp = VFLAG; + break; + case 0x7: /* VC */ + temp = !VFLAG; + break; + case 0x4: /* MI */ + temp = NFLAG; + break; + case 0x5: /* PL */ + temp = !NFLAG; + break; + case 0x2: /* CS */ + temp = CFLAG; + break; + case 0x3: /* CC */ + temp = !CFLAG; + break; + case 0x8: /* HI */ + temp = (CFLAG && !ZFLAG); + break; + case 0x9: /* LS */ + temp = (!CFLAG || ZFLAG); + break; + case 0xa: /* GE */ + temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); + break; + case 0xb: /* LT */ + temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); + break; + case 0xc: /* GT */ + temp = ((!NFLAG && !VFLAG && !ZFLAG) + || (NFLAG && VFLAG && !ZFLAG)); + break; + case 0xd: /* LE */ + temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) + || ZFLAG; + break; + case 0xe: /* AL */ + temp = 1; + break; + case 0xf: +// DEBUG_LOG(ARM11, "inst is %x\n"); +// DEBUG_LOG(ARM11, "icounter is %lld\n", cpu->icounter); +// CITRA_IGNORE_EXIT(-1); + temp = 1; + break; + } + return temp; +} + +enum DECODE_STATUS { + DECODE_SUCCESS, + DECODE_FAILURE +}; + +int decode_arm_instr(uint32_t instr, int32_t *idx); + +shtop_fp_t get_shtop(unsigned int inst) +{ + if (BIT(inst, 25)) { + return DPO(Immediate); + } else if (BITS(inst, 4, 11) == 0) { + return DPO(Register); + } else if (BITS(inst, 4, 6) == 0) { + return DPO(LogicalShiftLeftByImmediate); + } else if (BITS(inst, 4, 7) == 1) { + return DPO(LogicalShiftLeftByRegister); + } else if (BITS(inst, 4, 6) == 2) { + return DPO(LogicalShiftRightByImmediate); + } else if (BITS(inst, 4, 7) == 3) { + return DPO(LogicalShiftRightByRegister); + } else if (BITS(inst, 4, 6) == 4) { + return DPO(ArithmeticShiftRightByImmediate); + } else if (BITS(inst, 4, 7) == 5) { + return DPO(ArithmeticShiftRightByRegister); + } else if (BITS(inst, 4, 6) == 6) { + return DPO(RotateRightByImmediate); + } else if (BITS(inst, 4, 7) == 7) { + return DPO(RotateRightByRegister); + } + return NULL; +} + +get_addr_fp_t get_calc_addr_op(unsigned int inst) +{ + /* 1 */ + if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) { +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return LnSWoUB(ImmediateOffset); + } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { +// DEBUG_MSG; +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return LnSWoUB(RegisterOffset); + } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) { +// DEBUG_MSG; +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return LnSWoUB(ScaledRegisterOffset); + } else if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 1) { +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return LnSWoUB(ImmediatePreIndexed); + } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BITS(inst, 4, 11) == 0) { + return LnSWoUB(RegisterPreIndexed); + } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BIT(inst, 4) == 0) { + return LnSWoUB(ScaledRegisterPreIndexed); + } else if (BITS(inst, 24, 27) == 4 && BIT(inst, 21) == 0) { + return LnSWoUB(ImmediatePostIndexed); + } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { +// DEBUG_MSG; + return LnSWoUB(RegisterPostIndexed); + } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) { + return LnSWoUB(ScaledRegisterPostIndexed); +// DEBUG_MSG; + } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { + /* 2 */ +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return MLnS(ImmediateOffset); +// DEBUG_MSG; + } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { +// DEBUG_LOG(ARM11, "line is %d\n", __LINE__); + return MLnS(RegisterOffset); +// DEBUG_MSG; + } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 3 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { +// DEBUG_LOG(ARM11, "line is %d\n", __LINE__); + return MLnS(ImmediatePreIndexed); +// DEBUG_MSG; + } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 1 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { + return MLnS(RegisterPreIndexed); + } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { +// DEBUG_MSG; + return MLnS(ImmediatePostIndexed); + } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { + //DEBUG_MSG; + return MLnS(RegisterPostIndexed); + } else if (BITS(inst, 23, 27) == 0x11) { + /* 3 */ +// DEBUG_MSG; +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return LdnStM(IncrementAfter); + } else if (BITS(inst, 23, 27) == 0x13) { +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return LdnStM(IncrementBefore); +// DEBUG_MSG; + } else if (BITS(inst, 23, 27) == 0x10) { +// DEBUG_MSG; +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return LdnStM(DecrementAfter); + } else if (BITS(inst, 23, 27) == 0x12) { +// DEBUG_MSG; +// DEBUG_LOG(ARM11, "line is %d", __LINE__); + return LdnStM(DecrementBefore); + } + #if 0 + DEBUG_LOG(ARM11, "In %s Unknown addressing mode\n", __FUNCTION__); + DEBUG_LOG(ARM11, "inst:%x\n", inst); + CITRA_IGNORE_EXIT(-1); + #endif + return NULL; +} + +#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s) + +#define CHECK_RN (inst_cream->Rn == 15) +#define CHECK_RM (inst_cream->Rm == 15) +#define CHECK_RS (inst_cream->Rs == 15) + + +ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst)); + adc_inst *inst_cream = (adc_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + if (CHECK_RN) + inst_base->load_r15 = 1; + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst)); + add_inst *inst_cream = (add_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + if (CHECK_RN) + inst_base->load_r15 = 1; + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst)); + and_inst *inst_cream = (and_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + if (CHECK_RN) + inst_base->load_r15 = 1; + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index) +{ + #define POSBRANCH ((inst & 0x7fffff) << 2) + #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2) + + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst)); + bbl_inst *inst_cream = (bbl_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + + if (BIT(inst, 24)) + inst_base->br = CALL; + if (BITS(inst, 28, 31) <= 0xe) + inst_base->br |= COND; + + inst_cream->L = BIT(inst, 24); + inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst)); + bic_inst *inst_cream = (bic_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + if (CHECK_RN) + inst_base->load_r15 = 1; + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) + inst_base->br = INDIRECT_BRANCH; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst)); + blx_inst *inst_cream = (blx_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = INDIRECT_BRANCH; + + inst_cream->inst = inst; + if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { + inst_cream->val.Rm = BITS(inst, 0, 3); + } else { + inst_cream->val.signed_immed_24 = BITS(inst, 0, 23); + //DEBUG_LOG(ARM11, " blx inst is %x\n", inst); + //CITRA_IGNORE_EXIT(-1); +// DEBUG_MSG; + } + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst)); + bx_inst *inst_cream = (bx_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = INDIRECT_BRANCH; + + inst_cream->Rm = BITS(inst, 0, 3); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst)); + cdp_inst *inst_cream = (cdp_inst *)inst_base->component; + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->CRm = BITS(inst, 0, 3); + inst_cream->CRd = BITS(inst, 12, 15); + inst_cream->CRn = BITS(inst, 16, 19); + inst_cream->cp_num = BITS(inst, 8, 11); + inst_cream->opcode_2 = BITS(inst, 5, 7); + inst_cream->opcode_1 = BITS(inst, 20, 23); + inst_cream->inst = inst; + + DEBUG_LOG(ARM11, "in func %s inst %x index %x\n", __FUNCTION__, inst, index); + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst)); + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst)); + clz_inst *inst_cream = (clz_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 12, 15); + if (CHECK_RM) + inst_base->load_r15 = 1; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst)); + cmn_inst *inst_cream = (cmn_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + //inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + //inst_cream->Rd = BITS(inst, 12, 15); + if (CHECK_RN) + inst_base->load_r15 = 1; + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst)); + cmp_inst *inst_cream = (cmp_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->Rn = BITS(inst, 16, 19); + if (CHECK_RN) + inst_base->load_r15 = 1; + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst)); + cps_inst *inst_cream = (cps_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->imod0 = BIT(inst, 18); + inst_cream->imod1 = BIT(inst, 19); + inst_cream->mmod = BIT(inst, 17); + inst_cream->A = BIT(inst, 8); + inst_cream->I = BIT(inst, 7); + inst_cream->F = BIT(inst, 6); + inst_cream->mode = BITS(inst, 0, 4); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); + mov_inst *inst_cream = (mov_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst)); + eor_inst *inst_cream = (eor_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + if (CHECK_RN) + inst_base->load_r15 = 1; + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst)); + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BIT(inst, 15)) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); + sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->rotate = BITS(inst, 10, 11); + if (CHECK_RM) + inst_base->load_r15 = 1; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} + +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} + +ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); + uxth_inst *inst_cream = (uxth_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + if (CHECK_RM) + inst_base->load_r15 = 1; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst)); + uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + if (CHECK_RM || CHECK_RN) + inst_base->load_r15 = 1; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + if (I_BIT == 0) { + inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); + } else { + DEBUG_MSG; + } + #if 0 + inst_cream->get_addr = get_calc_addr_op(inst); + if(inst == 0x54f13001) { + DEBUG_LOG(ARM11, "get_calc_addr_op:%llx\n", inst_cream->get_addr); + } + #endif + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + return inst_base; +} + +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + //inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + if (I_BIT == 0) { + inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); + } else { + DEBUG_MSG; + } + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst)); + mcr_inst *inst_cream = (mcr_inst *)inst_base->component; + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->crn = BITS(inst, 16, 19); + inst_cream->crm = BITS(inst, 0, 3); + inst_cream->opcode_1 = BITS(inst, 21, 23); + inst_cream->opcode_2 = BITS(inst, 5, 7); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->cp_num = BITS(inst, 8, 11); + inst_cream->inst = inst; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst)); + mla_inst *inst_cream = (mla_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 12, 15); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->Rm = BITS(inst, 0, 3); + + if (CHECK_RM || CHECK_RN || CHECK_RS) + inst_base->load_r15 = 1; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); + mov_inst *inst_cream = (mov_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst)); + mrc_inst *inst_cream = (mrc_inst *)inst_base->component; + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->crn = BITS(inst, 16, 19); + inst_cream->crm = BITS(inst, 0, 3); + inst_cream->opcode_1 = BITS(inst, 21, 23); + inst_cream->opcode_2 = BITS(inst, 5, 7); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->cp_num = BITS(inst, 8, 11); + inst_cream->inst = inst; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst)); + mrs_inst *inst_cream = (mrs_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->R = BIT(inst, 22); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst)); + msr_inst *inst_cream = (msr_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->field_mask = BITS(inst, 16, 19); + inst_cream->R = BIT(inst, 22); + inst_cream->inst = inst; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst)); + mul_inst *inst_cream = (mul_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->Rd = BITS(inst, 16, 19); + + if (CHECK_RM || CHECK_RS) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst)); + mvn_inst *inst_cream = (mvn_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; + +} +ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst)); + orr_inst *inst_cream = (orr_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (CHECK_RN) + inst_base->load_r15 = 1; + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst)); + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); + rev_inst *inst_cream = (rev_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 12, 15); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); + rev_inst *inst_cream = (rev_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 12, 15); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst)); + rsb_inst *inst_cream = (rsb_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (CHECK_RN) + inst_base->load_r15 = 1; + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst)); + rsc_inst *inst_cream = (rsc_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (CHECK_RN) + inst_base->load_r15 = 1; + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst)); + sbc_inst *inst_cream = (sbc_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (CHECK_RN) + inst_base->load_r15 = 1; + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst)); + smla_inst *inst_cream = (smla_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->x = BIT(inst, 5); + inst_cream->y = BIT(inst, 6); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Rn = BITS(inst, 12, 15); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); + smlad_inst *inst_cream = (smlad_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->m = BIT(inst, 4); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Ra = BITS(inst, 12, 15); + + if (CHECK_RM ) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); + umlal_inst *inst_cream = (umlal_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->RdLo = BITS(inst, 12, 15); + + if (CHECK_RM || CHECK_RS) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst)); + smul_inst *inst_cream = (smul_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rd = BITS(inst, 16, 19); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->Rm = BITS(inst, 0, 3); + + inst_cream->x = BIT(inst, 5); + inst_cream->y = BIT(inst, 6); + + if (CHECK_RM || CHECK_RS) + inst_base->load_r15 = 1; + return inst_base; + +} +ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); + umull_inst *inst_cream = (umull_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->RdLo = BITS(inst, 12, 15); + + if (CHECK_RM || CHECK_RS) + inst_base->load_r15 = 1; + return inst_base; +} + +ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); + smlad_inst *inst_cream = (smlad_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->m = BIT(inst, 6); + inst_cream->Rm = BITS(inst, 8, 11); + inst_cream->Rn = BITS(inst, 0, 3); + inst_cream->Rd = BITS(inst, 16, 19); + + if (CHECK_RM || CHECK_RN) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst)); + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); + sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->rotate = BITS(inst, 10, 11); + + if (CHECK_RM) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); + uxth_inst *inst_cream = (uxth_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + + if (CHECK_RM) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); + uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; +// inst_cream->get_addr = get_calc_addr_op(inst); + if (I_BIT == 0) { + inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); + } else { + DEBUG_MSG; + } + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + inst_cream->get_addr = get_calc_addr_op(inst); + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->inst = inst; + if (I_BIT == 0) { + inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); + } else { + DEBUG_MSG; + } + + if (BITS(inst, 12, 15) == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst)); + sub_inst *inst_cream = (sub_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + if (CHECK_RN) + inst_base->load_r15 = 1; + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst)); + swi_inst *inst_cream = (swi_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->num = BITS(inst, 0, 23); + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); + swp_inst *inst_cream = (swp_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); + swp_inst *inst_cream = (swp_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->Rm = BITS(inst, 0, 3); + + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); + sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index){ + DEBUG_LOG(ARM11, "in func %s, SXTAH untested\n", __func__); + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst)); + sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->rotate = BITS(inst, 10, 11); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rn = BITS(inst, 16, 19); + + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst)); + teq_inst *inst_cream = (teq_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + + if (CHECK_RN) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst)); + tst_inst *inst_cream = (tst_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->I = BIT(inst, 25); + inst_cream->S = BIT(inst, 20); + inst_cream->Rn = BITS(inst, 16, 19); + inst_cream->Rd = BITS(inst, 12, 15); + inst_cream->shifter_operand = BITS(inst, 0, 11); + inst_cream->shtop_func = get_shtop(inst); + if (inst_cream->Rd == 15) { + inst_base->br = INDIRECT_BRANCH; + } + + if (CHECK_RN) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); + umlal_inst *inst_cream = (umlal_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->RdLo = BITS(inst, 12, 15); + + if (CHECK_RM || CHECK_RS) + inst_base->load_r15 = 1; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); + umull_inst *inst_cream = (umull_inst *)inst_base->component; + + inst_base->cond = BITS(inst, 28, 31); + inst_base->idx = index; + inst_base->br = NON_BRANCH; + inst_base->load_r15 = 0; + + inst_cream->S = BIT(inst, 20); + inst_cream->Rm = BITS(inst, 0, 3); + inst_cream->Rs = BITS(inst, 8, 11); + inst_cream->RdHi = BITS(inst, 16, 19); + inst_cream->RdLo = BITS(inst, 12, 15); + + if (CHECK_RM || CHECK_RS) + inst_base->load_r15 = 1; + return inst_base; +} + +ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb)); + b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; + + inst_cream->imm =((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); + //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + return inst_base; +} + +ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb)); + b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; + + inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0)); + inst_cream->cond = ((tinst >> 8) & 0xf); + //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x, cond=0x%x\n", __FUNCTION__, tinst, inst_cream->imm, inst_cream->cond); + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + return inst_base; +} + +ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb)); + bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; + + inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); + //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); + + inst_base->idx = index; + inst_base->br = NON_BRANCH; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb)); + bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; + + inst_cream->imm = (tinst & 0x07FF) << 1; + //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + return inst_base; +} +ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) +{ + arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb)); + blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component; + + inst_cream->imm = (tinst & 0x07FF) << 1; + //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); + inst_cream->instr = tinst; + inst_base->idx = index; + inst_base->br = DIRECT_BRANCH; + return inst_base; +} + +ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} +ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} + + + +/* Floating point VFPv3 structures and instructions */ + +#define VFP_INTERPRETER_STRUCT +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_INTERPRETER_STRUCT + +#define VFP_INTERPRETER_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_INTERPRETER_TRANS + + + +typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); + +const transop_fp_t arm_instruction_trans[] = { + #define VFP_INTERPRETER_TABLE + #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" + #undef VFP_INTERPRETER_TABLE + INTERPRETER_TRANSLATE(srs), + INTERPRETER_TRANSLATE(rfe), + INTERPRETER_TRANSLATE(bkpt), + INTERPRETER_TRANSLATE(blx), + INTERPRETER_TRANSLATE(cps), + INTERPRETER_TRANSLATE(pld), + INTERPRETER_TRANSLATE(setend), + INTERPRETER_TRANSLATE(clrex), + INTERPRETER_TRANSLATE(rev16), + INTERPRETER_TRANSLATE(usad8), + INTERPRETER_TRANSLATE(sxtb), + INTERPRETER_TRANSLATE(uxtb), + INTERPRETER_TRANSLATE(sxth), + INTERPRETER_TRANSLATE(sxtb16), + INTERPRETER_TRANSLATE(uxth), + INTERPRETER_TRANSLATE(uxtb16), + INTERPRETER_TRANSLATE(cpy), + INTERPRETER_TRANSLATE(uxtab), + INTERPRETER_TRANSLATE(ssub8), + INTERPRETER_TRANSLATE(shsub8), + INTERPRETER_TRANSLATE(ssubaddx), + INTERPRETER_TRANSLATE(strex), + INTERPRETER_TRANSLATE(strexb), + INTERPRETER_TRANSLATE(swp), + INTERPRETER_TRANSLATE(swpb), + INTERPRETER_TRANSLATE(ssub16), + INTERPRETER_TRANSLATE(ssat16), + INTERPRETER_TRANSLATE(shsubaddx), + INTERPRETER_TRANSLATE(qsubaddx), + INTERPRETER_TRANSLATE(shaddsubx), + INTERPRETER_TRANSLATE(shadd8), + INTERPRETER_TRANSLATE(shadd16), + INTERPRETER_TRANSLATE(sel), + INTERPRETER_TRANSLATE(saddsubx), + INTERPRETER_TRANSLATE(sadd8), + INTERPRETER_TRANSLATE(sadd16), + INTERPRETER_TRANSLATE(shsub16), + INTERPRETER_TRANSLATE(umaal), + INTERPRETER_TRANSLATE(uxtab16), + INTERPRETER_TRANSLATE(usubaddx), + INTERPRETER_TRANSLATE(usub8), + INTERPRETER_TRANSLATE(usub16), + INTERPRETER_TRANSLATE(usat16), + INTERPRETER_TRANSLATE(usada8), + INTERPRETER_TRANSLATE(uqsubaddx), + INTERPRETER_TRANSLATE(uqsub8), + INTERPRETER_TRANSLATE(uqsub16), + INTERPRETER_TRANSLATE(uqaddsubx), + INTERPRETER_TRANSLATE(uqadd8), + INTERPRETER_TRANSLATE(uqadd16), + INTERPRETER_TRANSLATE(sxtab), + INTERPRETER_TRANSLATE(uhsubaddx), + INTERPRETER_TRANSLATE(uhsub8), + INTERPRETER_TRANSLATE(uhsub16), + INTERPRETER_TRANSLATE(uhaddsubx), + INTERPRETER_TRANSLATE(uhadd8), + INTERPRETER_TRANSLATE(uhadd16), + INTERPRETER_TRANSLATE(uaddsubx), + INTERPRETER_TRANSLATE(uadd8), + INTERPRETER_TRANSLATE(uadd16), + INTERPRETER_TRANSLATE(sxtah), + INTERPRETER_TRANSLATE(sxtab16), + INTERPRETER_TRANSLATE(qadd8), + INTERPRETER_TRANSLATE(bxj), + INTERPRETER_TRANSLATE(clz), + INTERPRETER_TRANSLATE(uxtah), + INTERPRETER_TRANSLATE(bx), + INTERPRETER_TRANSLATE(rev), + INTERPRETER_TRANSLATE(blx), + INTERPRETER_TRANSLATE(revsh), + INTERPRETER_TRANSLATE(qadd), + INTERPRETER_TRANSLATE(qadd16), + INTERPRETER_TRANSLATE(qaddsubx), + INTERPRETER_TRANSLATE(ldrex), + INTERPRETER_TRANSLATE(qdadd), + INTERPRETER_TRANSLATE(qdsub), + INTERPRETER_TRANSLATE(qsub), + INTERPRETER_TRANSLATE(ldrexb), + INTERPRETER_TRANSLATE(qsub8), + INTERPRETER_TRANSLATE(qsub16), + INTERPRETER_TRANSLATE(smuad), + INTERPRETER_TRANSLATE(smmul), + INTERPRETER_TRANSLATE(smusd), + INTERPRETER_TRANSLATE(smlsd), + INTERPRETER_TRANSLATE(smlsld), + INTERPRETER_TRANSLATE(smmla), + INTERPRETER_TRANSLATE(smmls), + INTERPRETER_TRANSLATE(smlald), + INTERPRETER_TRANSLATE(smlad), + INTERPRETER_TRANSLATE(smlaw), + INTERPRETER_TRANSLATE(smulw), + INTERPRETER_TRANSLATE(pkhtb), + INTERPRETER_TRANSLATE(pkhbt), + INTERPRETER_TRANSLATE(smul), + INTERPRETER_TRANSLATE(smlalxy), + INTERPRETER_TRANSLATE(smla), + INTERPRETER_TRANSLATE(mcrr), + INTERPRETER_TRANSLATE(mrrc), + INTERPRETER_TRANSLATE(cmp), + INTERPRETER_TRANSLATE(tst), + INTERPRETER_TRANSLATE(teq), + INTERPRETER_TRANSLATE(cmn), + INTERPRETER_TRANSLATE(smull), + INTERPRETER_TRANSLATE(umull), + INTERPRETER_TRANSLATE(umlal), + INTERPRETER_TRANSLATE(smlal), + INTERPRETER_TRANSLATE(mul), + INTERPRETER_TRANSLATE(mla), + INTERPRETER_TRANSLATE(ssat), + INTERPRETER_TRANSLATE(usat), + INTERPRETER_TRANSLATE(mrs), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(and), + INTERPRETER_TRANSLATE(bic), + INTERPRETER_TRANSLATE(ldm), + INTERPRETER_TRANSLATE(eor), + INTERPRETER_TRANSLATE(add), + INTERPRETER_TRANSLATE(rsb), + INTERPRETER_TRANSLATE(rsc), + INTERPRETER_TRANSLATE(sbc), + INTERPRETER_TRANSLATE(adc), + INTERPRETER_TRANSLATE(sub), + INTERPRETER_TRANSLATE(orr), + INTERPRETER_TRANSLATE(mvn), + INTERPRETER_TRANSLATE(mov), + INTERPRETER_TRANSLATE(stm), + INTERPRETER_TRANSLATE(ldm), + INTERPRETER_TRANSLATE(ldrsh), + INTERPRETER_TRANSLATE(stm), + INTERPRETER_TRANSLATE(ldm), + INTERPRETER_TRANSLATE(ldrsb), + INTERPRETER_TRANSLATE(strd), + INTERPRETER_TRANSLATE(ldrh), + INTERPRETER_TRANSLATE(strh), + INTERPRETER_TRANSLATE(ldrd), + INTERPRETER_TRANSLATE(strt), + INTERPRETER_TRANSLATE(strbt), + INTERPRETER_TRANSLATE(ldrbt), + INTERPRETER_TRANSLATE(ldrt), + INTERPRETER_TRANSLATE(mrc), + INTERPRETER_TRANSLATE(mcr), + INTERPRETER_TRANSLATE(msr), + INTERPRETER_TRANSLATE(ldrb), + INTERPRETER_TRANSLATE(strb), + INTERPRETER_TRANSLATE(ldr), + INTERPRETER_TRANSLATE(ldrcond), + INTERPRETER_TRANSLATE(str), + INTERPRETER_TRANSLATE(cdp), + INTERPRETER_TRANSLATE(stc), + INTERPRETER_TRANSLATE(ldc), + INTERPRETER_TRANSLATE(swi), + INTERPRETER_TRANSLATE(bbl), + /* All the thumb instructions should be placed the end of table */ + INTERPRETER_TRANSLATE(b_2_thumb), + INTERPRETER_TRANSLATE(b_cond_thumb), + INTERPRETER_TRANSLATE(bl_1_thumb), + INTERPRETER_TRANSLATE(bl_2_thumb), + INTERPRETER_TRANSLATE(blx_1_thumb) +}; + +typedef map<unsigned int, int> bb_map; +bb_map CreamCache[65536]; +bb_map ProfileCache[65536]; + +//#define USE_DUMMY_CACHE + +#ifdef USE_DUMMY_CACHE +unsigned int DummyCache[0x100000]; +#endif + +#define HASH(x) ((x + (x << 3) + (x >> 6)) % 65536) +void insert_bb(unsigned int addr, int start) +{ +#ifdef USE_DUMMY_CACHE + DummyCache[addr] = start; +#else +// CreamCache[addr] = start; + CreamCache[HASH(addr)][addr] = start; +#endif +} + +#define TRANS_THRESHOLD 65000 +int find_bb(unsigned int addr, int &start) +{ + int ret = -1; +#ifdef USE_DUMMY_CACHE + start = DummyCache[addr]; + if (start) { + ret = 0; + } else + ret = -1; +#else + bb_map::const_iterator it = CreamCache[HASH(addr)].find(addr); + if (it != CreamCache[HASH(addr)].end()) { + start = static_cast<int>(it->second); + ret = 0; +#if HYBRID_MODE +#if PROFILE +#else + /* increase the bb counter */ + if(get_bb_prof(cpu, addr, 1) == TRANS_THRESHOLD){ + push_to_compiled(cpu, addr); + } +#endif +#endif + } else { + ret = -1; + } +#endif + return ret; +} + + +enum { + FETCH_SUCCESS, + FETCH_FAILURE +}; +static tdstate decode_thumb_instr(arm_processor *cpu, uint32_t inst, addr_t addr, uint32_t *arm_inst, uint32_t* inst_size, ARM_INST_PTR* ptr_inst_base){ + /* Check if in Thumb mode. */ + tdstate ret; + ret = thumb_translate (addr, inst, arm_inst, inst_size); + if(ret == t_branch){ + /* FIXME, endian should be judged */ + uint32 tinstr; + if((addr & 0x3) != 0) + tinstr = inst >> 16; + else + tinstr = inst & 0xFFFF; + + //tinstr = inst & 0xFFFF; + int inst_index; + /* table_length */ + int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); + + switch((tinstr & 0xF800) >> 11){ + /* we will translate the thumb instruction directly here */ + /* we will translate the thumb instruction directly here */ + case 26: + case 27: + if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ + uint32 cond = (tinstr & 0x0F00) >> 8; + inst_index = table_length - 4; + //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index); + *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); + } + else{ + /* something wrong */ + DEBUG_LOG(ARM11, "In %s, thumb decoder error\n", __FUNCTION__); + } + break; + case 28: + /* Branch 2, unconditional branch */ + inst_index = table_length - 5; + //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index); + *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); + break; + + case 8: + case 29: + /* For BLX 1 thumb instruction*/ + inst_index = table_length - 1; + //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc); + *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); + break; + case 30: + /* For BL 1 thumb instruction*/ + inst_index = table_length - 3; + //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc); + *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); + break; + case 31: + /* For BL 2 thumb instruction*/ + inst_index = table_length - 2; + //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 2 thumb index=%d, px=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc); + *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); + break; + default: + ret = t_undefined; + break; + } + } + return ret; +} + +#if 0 +int FetchInst(cpu_t *core, unsigned int &inst) +{ + //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t"); + arm_processor *cpu = (arm_processor *)(core->cpu_data->obj); +// fault_t fault = interpreter_read_memory(cpu->translate_pc, inst, 32); + fault_t fault = interpreter_fetch(core, cpu->translate_pc, inst, 32); + if (!core->is_user_mode) { + if (fault) { + cpu->abortSig = true; + cpu->Aborted = ARMul_PrefetchAbortV; + cpu->AbortAddr = cpu->translate_pc; + cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; + cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->translate_pc; + return FETCH_FAILURE; + } + } + return FETCH_SUCCESS; +} +#endif + +unsigned int *InstLength; + +enum { + KEEP_GOING, + FETCH_EXCEPTION +}; + +typedef struct instruction_set_encoding_item ISEITEM; + +extern const ISEITEM arm_instruction[]; + +vector<uint64_t> code_page_set; + +void flush_bb(uint32_t addr) +{ + bb_map::iterator it; + uint32_t start; + + addr &= 0xfffff000; + for (int i = 0; i < 65536; i ++) { + for (it = CreamCache[i].begin(); it != CreamCache[i].end(); ) { + start = static_cast<uint32_t>(it->first); + //start = (start >> 12) << 12; + start &= 0xfffff000; + if (start == addr) { + //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); + CreamCache[i].erase(it ++); + } else + ++it; + } + } + + for (int i = 0; i < 65536; i ++) { + for (it = ProfileCache[i].begin(); it != ProfileCache[i].end(); ) { + start = static_cast<uint32_t>(it->first); + //start = (start >> 12) << 12; + start &= 0xfffff000; + if (start == addr) { + //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); + ProfileCache[i].erase(it ++); + } else + ++it; + } + } + + //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr); +} + +//static uint32_t get_bank_addr(void *addr) +//{ +// uint64_t address = (uint64_t)addr; +// uint64_t bank0 = get_dma_addr(BANK0_START); +// if ((address >= bank0) && (address < (bank0 + BANK0_SIZE))) { +// //DEBUG_LOG(ARM11, "1.addr is %llx\n", addr); +// return ((uint64_t)addr - bank0) + BANK0_START; +// } +// return 0; +//} + +/* shenoubang add win32 2012-6-12 */ +//#ifndef __WIN32__ +//static void flush_code_cache(int signal_number, siginfo_t *si, void *unused) +//{ +// DEBUG_LOG(ARM11, "in %s, addr=0x%llx\n", __FUNCTION__, si->si_addr); +// uint64_t addr = (uint64_t)si->si_addr; +// addr = (addr >> 12) << 12; +// skyeye_backtrace(); +// #if 0 +// if (addr == 0) { +// return; +// } +// const vector<uint64_t>::iterator it = find(code_page_set.begin(), +// code_page_set.end(), +// (uint64_t)addr); +// if (it != code_page_set.end()) { +// code_page_set.erase(it); +// } +// mprotect((void *)addr, 4096, PROT_READ | PROT_WRITE); +// //DEBUG_LOG(ARM11, "[flush][ADDR:0x%08llx]\n", addr); +// uint32_t phys_addr = get_bank_addr((void *)addr); +//// DEBUG_LOG(ARM11, "[PHYSICAL][ADDR:0x%08llx]\n", phys_addr); +// flush_bb(phys_addr); +// flush_bb(phys_addr + 4096); +//#if HYBRID_MODE +// /* flush the translated BB of dyncom */ +// clear_translated_cache(phys_addr); +//#endif +// #endif +//} +//#endif /* shenoubang */ + +//void protect_code_page(uint32_t addr) +//{ +// void *mem_ptr = (void *)get_dma_addr(addr); +// mem_ptr = (void *)((long long int)mem_ptr & 0xfffffffffffff000LL); +// +// const vector<uint64_t>::iterator it = find(code_page_set.begin(), +// code_page_set.end(), +// (uint64_t)mem_ptr); +// if (it != code_page_set.end()) { +// return; +// } +// //DEBUG_LOG(ARM11, "[mprotect][ADDR:0x%08llx]\n", mem_ptr); +// /* shenoubang add win32 2012-6-12 */ +//#ifndef __WIN32__ +// struct sigaction sa; +// +// memset(&sa, 0, sizeof(sa)); +// sa.sa_flags = SA_RESTART | SA_SIGINFO; +// sa.sa_sigaction = &flush_code_cache; +// sigaction(SIGSEGV, &sa, NULL); +// +// //mprotect(mem_ptr, 4096, PROT_READ); +// +// code_page_set.push_back((uint64_t)mem_ptr); +//#endif /* shenoubang */ +//} + + + +int InterpreterTranslate(arm_processor *cpu, int &bb_start, addr_t addr) +{ + /* Decode instruction, get index */ + /* Allocate memory and init InsCream */ + /* Go on next, until terminal instruction */ + /* Save start addr of basicblock in CreamCache */ + //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t"); + //arm_processor *cpu = (arm_processor *)(core->cpu_data->obj); + ARM_INST_PTR inst_base = NULL; + unsigned int inst, inst_size = 4; + int idx; + int ret = NON_BRANCH; + int thumb = 0; + /* instruction size of basic block */ + int size = 0; + /* (R15 - 8) ? */ + //cpu->translate_pc = cpu->Reg[15]; + bb_start = top; + + if (cpu->TFlag) + thumb = THUMB; + + addr_t phys_addr; + addr_t pc_start; + fault_t fault = NO_FAULT; + //fault = check_address_validity(cpu, addr, &phys_addr, 1, INSN_TLB); + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if(fault != NO_FAULT){ + cpu->abortSig = true; + cpu->Aborted = ARMul_PrefetchAbortV; + cpu->AbortAddr = addr; + cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; + cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr; + return FETCH_EXCEPTION; + } + pc_start = phys_addr; + //phys_addr = get_dma_addr(phys_addr); + while(ret == NON_BRANCH) { + /* shenoubang add win32 2012-6-14 */ +#ifdef __WIN32__ + mem_bank_t* bank; + if (bank = bank_ptr(addr)) { + bank->bank_read(32, phys_addr, &inst); + } + else { + DEBUG_LOG(ARM11, "SKYEYE: Read physical addr 0x%x error!!\n", phys_addr); + return FETCH_FAILURE; + } +#else + inst = Memory::Read32(phys_addr & 0xFFFFFFFC);//*(uint32_t *)(phys_addr & 0xFFFFFFFC); +#endif + //or_tag(core, phys_addr, TAG_FAST_INTERP); + + /*if (ret == FETCH_FAILURE) { + return FETCH_EXCEPTION; + }*/ + + size ++; + /* If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction */ + if (cpu->TFlag){ + //if(cpu->Cpsr & (1 << THUMB_BIT)){ + uint32_t arm_inst; + tdstate state; + state = decode_thumb_instr(cpu, inst, phys_addr, &arm_inst, &inst_size, &inst_base); + //or_tag(core, phys_addr, TAG_THUMB); + //DEBUG_LOG(ARM11, "In thumb state, arm_inst=0x%x, inst_size=0x%x, pc=0x%x\n", arm_inst, inst_size, cpu->translate_pc); + /* we have translated the branch instruction of thumb in thumb decoder */ + if(state == t_branch){ + goto translated; + } + inst = arm_inst; + } + + ret = decode_arm_instr(inst, &idx); + if (ret == DECODE_FAILURE) { + DEBUG_LOG(ARM11, "[info] : Decode failure.\tPC : [0x%x]\tInstruction : [%x]\n", phys_addr, inst); + DEBUG_LOG(ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x\n", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]); + CITRA_IGNORE_EXIT(-1); + } +// DEBUG_LOG(ARM11, "PC : [0x%x] INST : %s\n", cpu->translate_pc, arm_instruction[idx].name); + inst_base = arm_instruction_trans[idx](inst, idx); +// DEBUG_LOG(ARM11, "translated @ %x INST : %x\n", cpu->translate_pc, inst); +// DEBUG_LOG(ARM11, "inst size is %d\n", InstLength[idx]); +translated: + phys_addr += inst_size; + + if ((phys_addr & 0xfff) == 0) { + inst_base->br = END_OF_PAGE; + } + ret = inst_base->br; + }; + + //DEBUG_LOG(ARM11, "In %s,insert_bb pc=0x%x, TFlag=0x%x\n", __FUNCTION__, pc_start, cpu->TFlag); + insert_bb(pc_start, bb_start); + return KEEP_GOING; +} + +#define LOG_IN_CLR skyeye_printf_in_color + +int cmp(const void *x, const void *y) +{ + return *(unsigned long long int*)x - *(unsigned long long int *)y; +} + +void InterpreterInitInstLength(unsigned long long int *ptr, size_t size) +{ + int array_size = size / sizeof(void *); + unsigned long long int *InstLabel = new unsigned long long int[array_size]; + memcpy(InstLabel, ptr, size); + qsort(InstLabel, array_size, sizeof(void *), cmp); + InstLength = new unsigned int[array_size - 4]; + for (int i = 0; i < array_size - 4; i ++) { + for (int j = 0; j < array_size; j ++) { + if (ptr[i] == InstLabel[j]) { + InstLength[i] = InstLabel[j + 1] - InstLabel[j]; + break; + } + } + } + for (int i = 0; i < array_size - 4; i ++) + DEBUG_LOG(ARM11, "[%d]:%d\n", i, InstLength[i]); +} + +int clz(unsigned int x) +{ + int n; + if (x == 0) return (32); + n = 1; + if ((x >> 16) == 0) { n = n + 16; x = x << 16;} + if ((x >> 24) == 0) { n = n + 8; x = x << 8;} + if ((x >> 28) == 0) { n = n + 4; x = x << 4;} + if ((x >> 30) == 0) { n = n + 2; x = x << 2;} + n = n - (x >> 31); + return n; +} + +unsigned arm_dyncom_SWI (ARMul_State * state, ARMword number); + +static bool InAPrivilegedMode(arm_core_t *core) +{ + return (core->Mode != USER32MODE); +} + +/* r15 = r15 + 8 */ +unsigned InterpreterMainLoop(ARMul_State* state) +{ + #define CRn inst_cream->crn + #define OPCODE_2 inst_cream->opcode_2 + #define CRm inst_cream->crm + #define CP15_REG(n) cpu->CP15[CP15(n)] + #define RD cpu->Reg[inst_cream->Rd] + #define RN cpu->Reg[inst_cream->Rn] + #define RM cpu->Reg[inst_cream->Rm] + #define RS cpu->Reg[inst_cream->Rs] + #define RDHI cpu->Reg[inst_cream->RdHi] + #define RDLO cpu->Reg[inst_cream->RdLo] + #define LINK_RTN_ADDR (cpu->Reg[14] = cpu->Reg[15] + 4) + #define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24) + #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand) + + #if ENABLE_ICOUNTER + #define INC_ICOUNTER cpu->icounter++; \ + if(cpu->Reg[15] > 0xc0000000) \ + cpu->kernel_icounter++; + //if (debug_function(core)) \ + if (core->check_int_flag) \ + goto END + //DEBUG_LOG(ARM11, "icounter is %llx line is %d pc is %x\n", cpu->icounter, __LINE__, cpu->Reg[15]) + #else + #define INC_ICOUNTER ; + #endif + + #define FETCH_INST if (inst_base->br != NON_BRANCH) \ + goto DISPATCH; \ + inst_base = (arm_inst *)&inst_buf[ptr] +#define INC_PC(l) ptr += sizeof(arm_inst) + l + +// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a +// clunky switch statement. +#if defined __GNUC__ || defined __clang__ +#define GOTO_NEXT_INST \ + if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ + num_instrs++; \ + goto *InstLabel[inst_base->idx] +#else +#define GOTO_NEXT_INST \ + if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ + num_instrs++; \ + switch(inst_base->idx) { \ + case 0: goto VMLA_INST; \ + case 1: goto VMLS_INST; \ + case 2: goto VNMLA_INST; \ + case 3: goto VNMLA_INST; \ + case 4: goto VNMLS_INST; \ + case 5: goto VNMUL_INST; \ + case 6: goto VMUL_INST; \ + case 7: goto VADD_INST; \ + case 8: goto VSUB_INST; \ + case 9: goto VDIV_INST; \ + case 10: goto VMOVI_INST; \ + case 11: goto VMOVR_INST; \ + case 12: goto VABS_INST; \ + case 13: goto VNEG_INST; \ + case 14: goto VSQRT_INST; \ + case 15: goto VCMP_INST; \ + case 16: goto VCMP2_INST; \ + case 17: goto VCVTBDS_INST; \ + case 18: goto VCVTBFF_INST; \ + case 19: goto VCVTBFI_INST; \ + case 20: goto VMOVBRS_INST; \ + case 21: goto VMSR_INST; \ + case 22: goto VMOVBRC_INST; \ + case 23: goto VMRS_INST; \ + case 24: goto VMOVBCR_INST; \ + case 25: goto VMOVBRRSS_INST; \ + case 26: goto VMOVBRRD_INST; \ + case 27: goto VSTR_INST; \ + case 28: goto VPUSH_INST; \ + case 29: goto VSTM_INST; \ + case 30: goto VPOP_INST; \ + case 31: goto VLDR_INST; \ + case 32: goto VLDM_INST ; \ + case 33: goto SRS_INST; \ + case 34: goto RFE_INST; \ + case 35: goto BKPT_INST; \ + case 36: goto BLX_INST; \ + case 37: goto CPS_INST; \ + case 38: goto PLD_INST; \ + case 39: goto SETEND_INST; \ + case 40: goto CLREX_INST; \ + case 41: goto REV16_INST; \ + case 42: goto USAD8_INST; \ + case 43: goto SXTB_INST; \ + case 44: goto UXTB_INST; \ + case 45: goto SXTH_INST; \ + case 46: goto SXTB16_INST; \ + case 47: goto UXTH_INST; \ + case 48: goto UXTB16_INST; \ + case 49: goto CPY_INST; \ + case 50: goto UXTAB_INST; \ + case 51: goto SSUB8_INST; \ + case 52: goto SHSUB8_INST; \ + case 53: goto SSUBADDX_INST; \ + case 54: goto STREX_INST; \ + case 55: goto STREXB_INST; \ + case 56: goto SWP_INST; \ + case 57: goto SWPB_INST; \ + case 58: goto SSUB16_INST; \ + case 59: goto SSAT16_INST; \ + case 60: goto SHSUBADDX_INST; \ + case 61: goto QSUBADDX_INST; \ + case 62: goto SHADDSUBX_INST; \ + case 63: goto SHADD8_INST; \ + case 64: goto SHADD16_INST; \ + case 65: goto SEL_INST; \ + case 66: goto SADDSUBX_INST; \ + case 67: goto SADD8_INST; \ + case 68: goto SADD16_INST; \ + case 69: goto SHSUB16_INST; \ + case 70: goto UMAAL_INST; \ + case 71: goto UXTAB16_INST; \ + case 72: goto USUBADDX_INST; \ + case 73: goto USUB8_INST; \ + case 74: goto USUB16_INST; \ + case 75: goto USAT16_INST; \ + case 76: goto USADA8_INST; \ + case 77: goto UQSUBADDX_INST; \ + case 78: goto UQSUB8_INST; \ + case 79: goto UQSUB16_INST; \ + case 80: goto UQADDSUBX_INST; \ + case 81: goto UQADD8_INST; \ + case 82: goto UQADD16_INST; \ + case 83: goto SXTAB_INST; \ + case 84: goto UHSUBADDX_INST; \ + case 85: goto UHSUB8_INST; \ + case 86: goto UHSUB16_INST; \ + case 87: goto UHADDSUBX_INST; \ + case 88: goto UHADD8_INST; \ + case 89: goto UHADD16_INST; \ + case 90: goto UADDSUBX_INST; \ + case 91: goto UADD8_INST; \ + case 92: goto UADD16_INST; \ + case 93: goto SXTAH_INST; \ + case 94: goto SXTAB16_INST; \ + case 95: goto QADD8_INST; \ + case 96: goto BXJ_INST; \ + case 97: goto CLZ_INST; \ + case 98: goto UXTAH_INST; \ + case 99: goto BX_INST; \ + case 100: goto REV_INST; \ + case 101: goto BLX_INST; \ + case 102: goto REVSH_INST; \ + case 103: goto QADD_INST; \ + case 104: goto QADD16_INST; \ + case 105: goto QADDSUBX_INST; \ + case 106: goto LDREX_INST; \ + case 107: goto QDADD_INST; \ + case 108: goto QDSUB_INST; \ + case 109: goto QSUB_INST; \ + case 110: goto LDREXB_INST; \ + case 111: goto QSUB8_INST; \ + case 112: goto QSUB16_INST; \ + case 113: goto SMUAD_INST; \ + case 114: goto SMMUL_INST; \ + case 115: goto SMUSD_INST; \ + case 116: goto SMLSD_INST; \ + case 117: goto SMLSLD_INST; \ + case 118: goto SMMLA_INST; \ + case 119: goto SMMLS_INST; \ + case 120: goto SMLALD_INST; \ + case 121: goto SMLAD_INST; \ + case 122: goto SMLAW_INST; \ + case 123: goto SMULW_INST; \ + case 124: goto PKHTB_INST; \ + case 125: goto PKHBT_INST; \ + case 126: goto SMUL_INST; \ + case 127: goto SMLAL_INST; \ + case 128: goto SMLA_INST; \ + case 129: goto MCRR_INST; \ + case 130: goto MRRC_INST; \ + case 131: goto CMP_INST; \ + case 132: goto TST_INST; \ + case 133: goto TEQ_INST; \ + case 134: goto CMN_INST; \ + case 135: goto SMULL_INST; \ + case 136: goto UMULL_INST; \ + case 137: goto UMLAL_INST; \ + case 138: goto SMLAL_INST; \ + case 139: goto MUL_INST; \ + case 140: goto MLA_INST; \ + case 141: goto SSAT_INST; \ + case 142: goto USAT_INST; \ + case 143: goto MRS_INST; \ + case 144: goto MSR_INST; \ + case 145: goto AND_INST; \ + case 146: goto BIC_INST; \ + case 147: goto LDM_INST; \ + case 148: goto EOR_INST; \ + case 149: goto ADD_INST; \ + case 150: goto RSB_INST; \ + case 151: goto RSC_INST; \ + case 152: goto SBC_INST; \ + case 153: goto ADC_INST; \ + case 154: goto SUB_INST; \ + case 155: goto ORR_INST; \ + case 156: goto MVN_INST; \ + case 157: goto MOV_INST; \ + case 158: goto STM_INST; \ + case 159: goto LDM_INST; \ + case 160: goto LDRSH_INST; \ + case 161: goto STM_INST; \ + case 162: goto LDM_INST; \ + case 163: goto LDRSB_INST; \ + case 164: goto STRD_INST; \ + case 165: goto LDRH_INST; \ + case 166: goto STRH_INST; \ + case 167: goto LDRD_INST; \ + case 168: goto STRT_INST; \ + case 169: goto STRBT_INST; \ + case 170: goto LDRBT_INST; \ + case 171: goto LDRT_INST; \ + case 172: goto MRC_INST; \ + case 173: goto MCR_INST; \ + case 174: goto MSR_INST; \ + case 175: goto LDRB_INST; \ + case 176: goto STRB_INST; \ + case 177: goto LDR_INST; \ + case 178: goto LDRCOND_INST ; \ + case 179: goto STR_INST; \ + case 180: goto CDP_INST; \ + case 181: goto STC_INST; \ + case 182: goto LDC_INST; \ + case 183: goto SWI_INST; \ + case 184: goto BBL_INST; \ + case 185: goto B_2_THUMB ; \ + case 186: goto B_COND_THUMB ; \ + case 187: goto BL_1_THUMB ; \ + case 188: goto BL_2_THUMB ; \ + case 189: goto BLX_1_THUMB ; \ + case 190: goto DISPATCH; \ + case 191: goto INIT_INST_LENGTH; \ + case 192: goto END; \ + } +#endif + + #define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0) + #define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1) +// #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((ISNEG(lop) && ISPOS(rop)) || \ + (ISNEG(lop) && ISPOS(dst)) || \ + (ISPOS(rop) && ISPOS(dst)))) + #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((dst < lop) || (dst < rop))) + #define UPDATE_CFLAG_CARRY_FROM_ADD(lop, rop, flag) (cpu->CFlag = (((uint64_t) lop + (uint64_t) rop + (uint64_t) flag) > 0xffffffff) ) + #define UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(lop, rop, flag) (cpu->CFlag = ((uint64_t) lop >= ((uint64_t) rop + (uint64_t) flag))) + #define UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop) (cpu->CFlag = (lop >= rop)) + #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) (cpu->CFlag = !(dst < lop)) + #define UPDATE_CFLAG_WITH_SC cpu->CFlag = cpu->shifter_carry_out +// #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || \ + (ISNEG(lop) && ISPOS(dst)) || \ + (ISPOS(rop) && ISPOS(dst))) + #define UPDATE_VFLAG(dst, lop, rop) (cpu->VFlag = (((lop < 0) && (rop < 0) && (dst >= 0)) || \ + ((lop >= 0) && (rop) >= 0 && (dst < 0)))) + #define UPDATE_VFLAG_WITH_NOT(dst, lop, rop) (cpu->VFlag = !(((lop < 0) && (rop < 0) && (dst >= 0)) || \ + ((lop >= 0) && (rop) >= 0 && (dst < 0)))) + #define UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop) (cpu->VFlag = (((lop ^ rop) & (lop ^ dst)) >> 31)) + + #define SAVE_NZCVT cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | \ + (cpu->NFlag << 31) | \ + (cpu->ZFlag << 30) | \ + (cpu->CFlag << 29) | \ + (cpu->VFlag << 28) | \ + (cpu->TFlag << 5) + #define LOAD_NZCVT cpu->NFlag = (cpu->Cpsr >> 31); \ + cpu->ZFlag = (cpu->Cpsr >> 30) & 1; \ + cpu->CFlag = (cpu->Cpsr >> 29) & 1; \ + cpu->VFlag = (cpu->Cpsr >> 28) & 1; \ + cpu->TFlag = (cpu->Cpsr >> 5) & 1; + + #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE) + #define PC (cpu->Reg[15]) + #define CHECK_EXT_INT if (!cpu->NirqSig) { \ + if (!(cpu->Cpsr & 0x80)) { \ + goto END; \ + } \ + } + + + + //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t"); + arm_processor *cpu = state; //(arm_processor *)(core->cpu_data->obj); + + // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback + // to a clunky switch statement. +#if defined __GNUC__ || defined __clang__ + void *InstLabel[] = { + #define VFP_INTERPRETER_LABEL + #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" + #undef VFP_INTERPRETER_LABEL + &&SRS_INST,&&RFE_INST,&&BKPT_INST,&&BLX_INST,&&CPS_INST,&&PLD_INST,&&SETEND_INST,&&CLREX_INST,&&REV16_INST,&&USAD8_INST,&&SXTB_INST, + &&UXTB_INST,&&SXTH_INST,&&SXTB16_INST,&&UXTH_INST,&&UXTB16_INST,&&CPY_INST,&&UXTAB_INST,&&SSUB8_INST,&&SHSUB8_INST,&&SSUBADDX_INST, + &&STREX_INST,&&STREXB_INST,&&SWP_INST,&&SWPB_INST,&&SSUB16_INST,&&SSAT16_INST,&&SHSUBADDX_INST,&&QSUBADDX_INST,&&SHADDSUBX_INST, + &&SHADD8_INST,&&SHADD16_INST,&&SEL_INST,&&SADDSUBX_INST,&&SADD8_INST,&&SADD16_INST,&&SHSUB16_INST,&&UMAAL_INST,&&UXTAB16_INST, + &&USUBADDX_INST,&&USUB8_INST,&&USUB16_INST,&&USAT16_INST,&&USADA8_INST,&&UQSUBADDX_INST,&&UQSUB8_INST,&&UQSUB16_INST, + &&UQADDSUBX_INST,&&UQADD8_INST,&&UQADD16_INST,&&SXTAB_INST,&&UHSUBADDX_INST,&&UHSUB8_INST,&&UHSUB16_INST,&&UHADDSUBX_INST,&&UHADD8_INST, + &&UHADD16_INST,&&UADDSUBX_INST,&&UADD8_INST,&&UADD16_INST,&&SXTAH_INST,&&SXTAB16_INST,&&QADD8_INST,&&BXJ_INST,&&CLZ_INST,&&UXTAH_INST, + &&BX_INST,&&REV_INST,&&BLX_INST,&&REVSH_INST,&&QADD_INST,&&QADD16_INST,&&QADDSUBX_INST,&&LDREX_INST,&&QDADD_INST,&&QDSUB_INST, + &&QSUB_INST,&&LDREXB_INST,&&QSUB8_INST,&&QSUB16_INST,&&SMUAD_INST,&&SMMUL_INST,&&SMUSD_INST,&&SMLSD_INST,&&SMLSLD_INST,&&SMMLA_INST, + &&SMMLS_INST,&&SMLALD_INST,&&SMLAD_INST,&&SMLAW_INST,&&SMULW_INST,&&PKHTB_INST,&&PKHBT_INST,&&SMUL_INST,&&SMLAL_INST,&&SMLA_INST, + &&MCRR_INST,&&MRRC_INST,&&CMP_INST,&&TST_INST,&&TEQ_INST,&&CMN_INST,&&SMULL_INST,&&UMULL_INST,&&UMLAL_INST,&&SMLAL_INST,&&MUL_INST, + &&MLA_INST,&&SSAT_INST,&&USAT_INST,&&MRS_INST,&&MSR_INST,&&AND_INST,&&BIC_INST,&&LDM_INST,&&EOR_INST,&&ADD_INST,&&RSB_INST,&&RSC_INST, + &&SBC_INST,&&ADC_INST,&&SUB_INST,&&ORR_INST,&&MVN_INST,&&MOV_INST,&&STM_INST,&&LDM_INST,&&LDRSH_INST,&&STM_INST,&&LDM_INST,&&LDRSB_INST, + &&STRD_INST,&&LDRH_INST,&&STRH_INST,&&LDRD_INST,&&STRT_INST,&&STRBT_INST,&&LDRBT_INST,&&LDRT_INST,&&MRC_INST,&&MCR_INST,&&MSR_INST, + &&LDRB_INST,&&STRB_INST,&&LDR_INST,&&LDRCOND_INST, &&STR_INST,&&CDP_INST,&&STC_INST,&&LDC_INST,&&SWI_INST,&&BBL_INST,&&B_2_THUMB, &&B_COND_THUMB, + &&BL_1_THUMB, &&BL_2_THUMB, &&BLX_1_THUMB, &&DISPATCH,&&INIT_INST_LENGTH,&&END + }; +#endif + arm_inst * inst_base; + unsigned int lop, rop, dst; + unsigned int addr; + unsigned int phys_addr; + unsigned int last_pc = 0; + unsigned int num_instrs = 0; + fault_t fault; + static unsigned int last_physical_base = 0, last_logical_base = 0; + int ptr; + bool single_step = (cpu->NumInstrsToExecute == 1); + + LOAD_NZCVT; + DISPATCH: + { + if (!cpu->NirqSig) { + if (!(cpu->Cpsr & 0x80)) { + goto END; + } + } + + if (cpu->TFlag) { + cpu->Reg[15] &= 0xfffffffe; + } else + cpu->Reg[15] &= 0xfffffffc; +#if PROFILE + /* check next instruction address is valid. */ + last_pc = cpu->Reg[15]; +#endif +#if USER_MODE_OPT + phys_addr = cpu->Reg[15]; +#else + { + if (last_logical_base == (cpu->Reg[15] & 0xfffff000)) + phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff); + else { + /* check next instruction address is valid. */ + fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB); + if (fault) { + cpu->abortSig = true; + cpu->Aborted = ARMul_PrefetchAbortV; + cpu->AbortAddr = cpu->Reg[15]; + cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; + cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15]; + goto END; + } + last_logical_base = cpu->Reg[15] & 0xfffff000; + last_physical_base = phys_addr & 0xfffff000; + } + } +#if HYBRID_MODE + /* check if the native code of dyncom is available */ + //fast_map hash_map = core->dyncom_engine->fmap; + //void * pfunc = NULL; + //PFUNC(phys_addr); + //if(pfunc){ + if(is_translated_entry(core, phys_addr)){ + int rc = JIT_RETURN_NOERR; + //DEBUG_LOG(ARM11, "enter jit icounter is %lld, pc=0x%x\n", core->icounter, cpu->Reg[15]); + SAVE_NZCVT; +// resume_timing(); + rc = cpu_run(core); + LOAD_NZCVT; + //DEBUG_LOG(ARM11, "out of jit ret is %d icounter is %lld, pc=0x%x\n", rc, core->icounter, cpu->Reg[15]); + if((rc == JIT_RETURN_FUNCNOTFOUND) || (rc == JIT_RETURN_FUNC_BLANK)){ + /* keep the tflag same with the bit in CPSR */ + //cpu->TFlag = cpu->Cpsr & (1 << THUMB_BIT); + //cpu->TFlag = cpu->Cpsr & (1 << 5); + //switch_mode(cpu, cpu->Cpsr & 0x1f); + //DEBUG_LOG(ARM11, "FUNCTION not found , pc=0x%x\n", cpu->Reg[15]); + fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB); + if (fault) { + cpu->abortSig = true; + cpu->Aborted = ARMul_PrefetchAbortV; + cpu->AbortAddr = cpu->Reg[15]; + cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; + cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15]; + goto END; + } + last_logical_base = cpu->Reg[15] & 0xfffff000; + last_physical_base = phys_addr & 0xfffff000; + core->current_page_phys = last_physical_base; + core->current_page_effec = last_logical_base; + //push_to_compiled(core, phys_addr); + } + else{ + if((cpu->CP15[CP15(CP15_TLB_FAULT_STATUS)] & 0xf0)){ + //DEBUG_LOG(ARM11, "\n\n###############In %s, fsr=0x%x, fault_addr=0x%x, pc=0x%x\n\n", __FUNCTION__, cpu->CP15[CP15(CP15_FAULT_STATUS)], cpu->CP15[CP15(CP15_FAULT_ADDRESS)], cpu->Reg[15]); + //core->Reg[15] -= get_instr_size(cpu_dyncom); + fill_tlb(cpu); + goto END; + } + if (cpu->syscallSig) { + goto END; + } + if (cpu->abortSig) { + cpu->CP15[CP15_TLB_FAULT_STATUS - CP15_BASE] &= 0xFFFFFFF0; + goto END; + } + if (!cpu->NirqSig) { + if (!(cpu->Cpsr & 0x80)) { + goto END; + } + } + + /* if regular trap */ + cpu->Reg[15] += GET_INST_SIZE(cpu); + /*uint32_t mode = cpu->Cpsr & 0x1f; + if ((mode != cpu->Mode) && (!is_user_mode(core))) { + switch_mode(cpu, mode); + return 1; + }*/ + + goto END; + } + //phys_addr = cpu->Reg[15]; + } + else{ + if (last_logical_base == (cpu->Reg[15] & 0xfffff000)) + phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff); + else { + /* check next instruction address is valid. */ + fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB); + if (fault) { + cpu->abortSig = true; + cpu->Aborted = ARMul_PrefetchAbortV; + cpu->AbortAddr = cpu->Reg[15]; + cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; + cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15]; + goto END; + } + last_logical_base = cpu->Reg[15] & 0xfffff000; + last_physical_base = phys_addr & 0xfffff000; + } + } +#endif /* #if HYBRID_MODE */ +#endif /* #if USER_MODE_OPT */ + if (true){//if(is_fast_interp_code(core, phys_addr)){ + if (find_bb(phys_addr, ptr) == -1) + if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) + goto END; + } + else{ + if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) + goto END; + } +#if PROFILE + resume_timing(); +#endif + inst_base = (arm_inst *)&inst_buf[ptr]; + GOTO_NEXT_INST; + } + ADC_INST: + { + INC_ICOUNTER; + adc_inst *inst_cream = (adc_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + lop = RN; + unsigned int sht_op = SHIFTER_OPERAND; + rop = SHIFTER_OPERAND + cpu->CFlag; + RD = dst = lop + rop; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr */ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_CARRY_FROM_ADD(lop, sht_op, cpu->CFlag); + UPDATE_VFLAG((int)dst, (int)lop, (int)rop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(adc_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(adc_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + ADD_INST: + { + INC_ICOUNTER; + add_inst *inst_cream = (add_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + lop = RN; + if (inst_cream->Rn == 15) { + lop += 2 * GET_INST_SIZE(cpu); + } + rop = SHIFTER_OPERAND; + RD = dst = lop + rop; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr*/ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Cpsr & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG(dst, lop, rop); + UPDATE_VFLAG((int)dst, (int)lop, (int)rop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(add_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(add_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + AND_INST: + { + INC_ICOUNTER; + and_inst *inst_cream = (and_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + lop = RN; + rop = SHIFTER_OPERAND; + RD = dst = lop & rop; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr*/ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Cpsr & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_WITH_SC; + //UPDATE_VFLAG((int)dst, (int)lop, (int)rop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(and_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(and_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + BBL_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + bbl_inst *inst_cream = (bbl_inst *)inst_base->component; + if (inst_cream->L) { + LINK_RTN_ADDR; + } + SET_PC; + INC_PC(sizeof(bbl_inst)); + goto DISPATCH; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(bbl_inst)); + goto DISPATCH; + } + BIC_INST: + { + INC_ICOUNTER; + bic_inst *inst_cream = (bic_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + lop = RN; + if (inst_cream->Rn == 15) { + lop += 2 * GET_INST_SIZE(cpu); + } + rop = SHIFTER_OPERAND; +// RD = dst = lop & (rop ^ 0xffffffff); + RD = dst = lop & (~rop); + if ((inst_cream->S) && (inst_cream->Rd == 15)) { + /* cpsr = spsr */ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_WITH_SC; + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(bic_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(bic_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + BKPT_INST: + BLX_INST: + { + INC_ICOUNTER; + blx_inst *inst_cream = (blx_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + unsigned int inst = inst_cream->inst; + if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { + //LINK_RTN_ADDR; + cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); + if(cpu->TFlag) + cpu->Reg[14] |= 0x1; + cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe; + cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1; + //cpu->Reg[15] = cpu->Reg[BITS(inst, 0, 3)] & 0xfffffffe; + //cpu->TFlag = cpu->Reg[BITS(inst, 0, 3)] & 0x1; + } else { + cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); + cpu->TFlag = 0x1; + int signed_int = inst_cream->val.signed_immed_24; + signed_int = (signed_int) & 0x800000 ? (0x3F000000 | signed_int) : signed_int; + signed_int = signed_int << 2; + // cpu->Reg[15] = cpu->Reg[15] + 2 * GET_INST_SIZE(cpu) + cpu->Reg[15] = cpu->Reg[15] + 8 + + signed_int + (BIT(inst, 24) << 1); + //DEBUG_MSG; + } + INC_PC(sizeof(blx_inst)); + goto DISPATCH; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); +// INC_PC(sizeof(bx_inst)); + INC_PC(sizeof(blx_inst)); + goto DISPATCH; + } + BX_INST: + { + INC_ICOUNTER; + bx_inst *inst_cream = (bx_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (inst_cream->Rm == 15) + DEBUG_LOG(ARM11, "In %s, BX at pc %x: use of Rm = R15 is discouraged\n", __FUNCTION__, cpu->Reg[15]); + cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; + cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe; +// cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; + INC_PC(sizeof(bx_inst)); + goto DISPATCH; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); +// INC_PC(sizeof(bx_inst)); + INC_PC(sizeof(bx_inst)); + goto DISPATCH; + } + BXJ_INST: + CDP_INST: + { + INC_ICOUNTER; + cdp_inst *inst_cream = (cdp_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + /* FIXME, check if cp access allowed */ + #define CP_ACCESS_ALLOW 0 + if(CP_ACCESS_ALLOW){ + /* undefined instruction here */ + cpu->NumInstrsToExecute = 0; + return num_instrs; + } + ERROR_LOG(ARM11, "CDP insn inst=0x%x, pc=0x%x\n", inst_cream->inst, cpu->Reg[15]); + unsigned cpab = (cpu->CDP[inst_cream->cp_num]) (cpu, ARMul_FIRST, inst_cream->inst); + if(cpab != ARMul_DONE){ + ERROR_LOG(ARM11, "CDP insn wrong, inst=0x%x, cp_num=0x%x\n", inst_cream->inst, inst_cream->cp_num); + //CITRA_IGNORE_EXIT(-1); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(cdp_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + + CLREX_INST: + { + INC_ICOUNTER; + remove_exclusive(cpu, 0); + cpu->exclusive_state = 0; + + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(clrex_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + CLZ_INST: + { + INC_ICOUNTER; + clz_inst *inst_cream = (clz_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + RD = clz(RM); + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(clz_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + CMN_INST: + { + INC_ICOUNTER; + cmn_inst *inst_cream = (cmn_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { +// DEBUG_LOG(ARM11, "RN is %x\n", RN); + lop = RN; + rop = SHIFTER_OPERAND; + dst = lop + rop; + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG(dst, lop, rop); + UPDATE_VFLAG((int)dst, (int)lop, (int)rop); + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(cmn_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + CMP_INST: + { +// DEBUG_LOG(ARM11, "cmp inst\n"); +// DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]); + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { +// DEBUG_LOG(ARM11, "r0 is %x\n", cpu->Reg[0]); + cmp_inst *inst_cream = (cmp_inst *)inst_base->component; + lop = RN; + if (inst_cream->Rn == 15) { + lop += 2 * GET_INST_SIZE(cpu); + } + rop = SHIFTER_OPERAND; + dst = lop - rop; + + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); +// UPDATE_CFLAG(dst, lop, rop); + UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); +// UPDATE_VFLAG((int)dst, (int)lop, (int)rop); + UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); +// UPDATE_VFLAG_WITH_NOT(dst, lop, rop); + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(cmp_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + CPS_INST: + { + INC_ICOUNTER; + cps_inst *inst_cream = (cps_inst *)inst_base->component; + uint32_t aif_val = 0; + uint32_t aif_mask = 0; + if (InAPrivilegedMode(cpu)) { + /* isInAPrivilegedMode */ + if (inst_cream->imod1) { + if (inst_cream->A) { + aif_val |= (inst_cream->imod0 << 8); + aif_mask |= 1 << 8; + } + if (inst_cream->I) { + aif_val |= (inst_cream->imod0 << 7); + aif_mask |= 1 << 7; + } + if (inst_cream->F) { + aif_val |= (inst_cream->imod0 << 6); + aif_mask |= 1 << 6; + } + aif_mask = ~aif_mask; + cpu->Cpsr = (cpu->Cpsr & aif_mask) | aif_val; + } + if (inst_cream->mmod) { + cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode; + switch_mode(cpu, inst_cream->mode); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(cps_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + CPY_INST: + { + INC_ICOUNTER; + mov_inst *inst_cream = (mov_inst *)inst_base->component; +// cpy_inst *inst_cream = (cpy_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + RD = SHIFTER_OPERAND; +// RD = RM; + if ((inst_cream->Rd == 15)) { + INC_PC(sizeof(mov_inst)); + goto DISPATCH; + } + } +// DEBUG_LOG(ARM11, "cpy inst %x\n", cpu->Reg[15]); + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(mov_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + EOR_INST: + { + INC_ICOUNTER; + eor_inst *inst_cream = (eor_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + lop = RN; + if (inst_cream->Rn == 15) { + lop += 2 * GET_INST_SIZE(cpu); + } + rop = SHIFTER_OPERAND; + RD = dst = lop ^ rop; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr*/ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_WITH_SC; +// UPDATE_CFLAG(dst, lop, rop); +// UPDATE_VFLAG((int)dst, (int)lop, (int)rop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(eor_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(eor_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDC_INST: + { + INC_ICOUNTER; + /* NOT IMPL */ + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldc_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDM_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + int i; + unsigned int ret; + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) { + goto MMU_EXCEPTION; + } + unsigned int inst = inst_cream->inst; + if (BIT(inst, 22) && !BIT(inst, 15)) { +// DEBUG_MSG; + #if 1 + /* LDM (2) user */ + for (i = 0; i < 13; i++) { + if(BIT(inst, i)){ + #if 0 + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) { + goto MMU_EXCEPTION; + } + #endif + fault = interpreter_read_memory(addr, phys_addr, ret, 32); + //if (fault) goto MMU_EXCEPTION; + cpu->Reg[i] = ret; + addr += 4; + if ((addr & 0xfff) == 0) { + fault = check_address_validity(cpu, addr, &phys_addr, 1); + } else { + phys_addr += 4; + } + } + } + if (BIT(inst, 13)) { + #if 0 + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) { + goto MMU_EXCEPTION; + } + #endif + fault = interpreter_read_memory(addr, phys_addr, ret, 32); + //if (fault) goto MMU_EXCEPTION; + if (cpu->Mode == USER32MODE) + cpu->Reg[13] = ret; + else + cpu->Reg_usr[0] = ret; + addr += 4; + if ((addr & 0xfff) == 0) { + fault = check_address_validity(cpu, addr, &phys_addr, 1); + } else { + phys_addr += 4; + } + } + if (BIT(inst, 14)) { + #if 0 + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) { + goto MMU_EXCEPTION; + } + #endif + fault = interpreter_read_memory(addr, phys_addr, ret, 32); + //if (fault) goto MMU_EXCEPTION; + if (cpu->Mode == USER32MODE) + cpu->Reg[14] = ret; + else + cpu->Reg_usr[1] = ret; + } + #endif + } else if (!BIT(inst, 22)) { + for( i = 0; i < 16; i ++ ){ + if(BIT(inst, i)){ + //bus_read(32, addr, &ret); + #if 0 + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) { + goto MMU_EXCEPTION; + } + #endif + fault = interpreter_read_memory(addr, phys_addr, ret, 32); + if (fault) goto MMU_EXCEPTION; + /* For armv5t, should enter thumb when bits[0] is non-zero. */ + if(i == 15){ + cpu->TFlag = ret & 0x1; + ret &= 0xFFFFFFFE; + //DEBUG_LOG(ARM11, "In %s, TFlag ret=0x%x\n", __FUNCTION__, ret); + } + + cpu->Reg[i] = ret; + addr += 4; + if ((addr & 0xfff) == 0) { + fault = check_address_validity(cpu, addr, &phys_addr, 1); + } else { + phys_addr += 4; + } + } + } + } else if (BIT(inst, 22) && BIT(inst, 15)) { + for( i = 0; i < 15; i ++ ){ + if(BIT(inst, i)){ + #if 0 + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) { + goto MMU_EXCEPTION; + } + #endif + fault = interpreter_read_memory(addr, phys_addr, ret, 32); + //if (fault) goto MMU_EXCEPTION; + cpu->Reg[i] = ret; + addr += 4; + if ((addr & 0xfff) == 0) { + fault = check_address_validity(cpu, addr, &phys_addr, 1); + } else { + phys_addr += 4; + } + } + } + + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Cpsr & 0x1f); + LOAD_NZCVT; + } + #if 0 + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) { + goto MMU_EXCEPTION; + } + #endif + fault = interpreter_read_memory(addr, phys_addr, ret, 32); + if (fault) { + goto MMU_EXCEPTION; + } + cpu->Reg[15] = ret; + #if 0 + addr += 4; + phys_addr += 4; + #endif + } + if (BIT(inst, 15)) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SXTH_INST: + { + INC_ICOUNTER; + sxth_inst *inst_cream = (sxth_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate); + if (BIT(operand2, 15)) { + operand2 |= 0xffff0000; + } else { + operand2 &= 0xffff; + } + RD = operand2; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(sxth_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDR_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + //if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + //bus_read(32, addr, &value); + fault = interpreter_read_memory(addr, phys_addr, value, 32); + if (BIT(CP15_REG(CP15_CONTROL), 22) == 1) + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + else { + value = ROTATE_RIGHT_32(value,(8*(addr&0x3))); + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + } + if (BITS(inst_cream->inst, 12, 15) == 15) { + /* For armv5t, should enter thumb when bits[0] is non-zero. */ + cpu->TFlag = value & 0x1; + cpu->Reg[15] &= 0xFFFFFFFE; + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + //} + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDRCOND_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if (CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + //bus_read(32, addr, &value); + fault = interpreter_read_memory(addr, phys_addr, value, 32); + if (BIT(CP15_REG(CP15_CONTROL), 22) == 1) + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + else { + value = ROTATE_RIGHT_32(value,(8*(addr&0x3))); + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + } + + if (BITS(inst_cream->inst, 12, 15) == 15) { + /* For armv5t, should enter thumb when bits[0] is non-zero. */ + cpu->TFlag = value & 0x1; + cpu->Reg[15] &= 0xFFFFFFFE; + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + UXTH_INST: + { + INC_ICOUNTER; + uxth_inst *inst_cream = (uxth_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) + & 0xffff; + RD = operand2; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(uxth_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + UXTAH_INST: + { + INC_ICOUNTER; + uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) + & 0xffff; + RD = RN + operand2; + if (inst_cream->Rn == 15 || inst_cream->Rm == 15) { + DEBUG_LOG(ARM11, "in line %d\n", __LINE__); + CITRA_IGNORE_EXIT(-1); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(uxtah_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDRB_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 8); + if (fault) goto MMU_EXCEPTION; + //bus_read(8, addr, &value); + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + if (BITS(inst_cream->inst, 12, 15) == 15) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDRBT_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 8); + if (fault) goto MMU_EXCEPTION; + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + if (BITS(inst_cream->inst, 12, 15) == 15) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDRD_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + /* Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 || addr[2] == 0) */ + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + uint32_t rear_phys_addr; + fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 1); + if(fault){ + ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n"); + CITRA_IGNORE_EXIT(-1); + goto MMU_EXCEPTION; + } + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + fault = interpreter_read_memory(addr + 4, rear_phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = value; + /* No dispatch since this operation should not modify R15 */ + } + cpu->Reg[15] += 4; + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + + LDREX_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + + add_exclusive_addr(cpu, phys_addr); + cpu->exclusive_state = 1; + + //bus_read(32, addr, &value); + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + if (BITS(inst_cream->inst, 12, 15) == 15) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDREXB_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 8); + if (fault) goto MMU_EXCEPTION; + + add_exclusive_addr(cpu, phys_addr); + cpu->exclusive_state = 1; + + //bus_read(8, addr, &value); + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + if (BITS(inst_cream->inst, 12, 15) == 15) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDRH_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value = 0; + fault = interpreter_read_memory(addr, phys_addr, value, 16); +// fault = interpreter_read_memory(addr, value, 32); + if (fault) goto MMU_EXCEPTION; + //if (value == 0xffff && cpu->icounter > 190000000 && cpu->icounter < 210000000) { + // value = 0xffffffff; + //} + //bus_read(16, addr, &value); +// cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value & 0xffff; + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + if (BITS(inst_cream->inst, 12, 15) == 15) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDRSB_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; +// DEBUG_LOG(ARM11, "ldrsb addr is %x\n", addr); + fault = interpreter_read_memory(addr, phys_addr, value, 8); + if (fault) goto MMU_EXCEPTION; + //bus_read(8, addr, &value); + if (BIT(value, 7)) { + value |= 0xffffff00; + } + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + if (BITS(inst_cream->inst, 12, 15) == 15) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDRSH_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 16); + if (fault) goto MMU_EXCEPTION; + //bus_read(16, addr, &value); + if (BIT(value, 15)) { + value |= 0xffff0000; + } + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + if (BITS(inst_cream->inst, 12, 15) == 15) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + LDRT_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + + if (BIT(CP15_REG(CP15_CONTROL), 22) == 1) + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; + else + cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ROTATE_RIGHT_32(value,(8*(addr&0x3))) ; + + if (BITS(inst_cream->inst, 12, 15) == 15) { + INC_PC(sizeof(ldst_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + MCR_INST: + { + INC_ICOUNTER; + /* NOT IMPL */ + mcr_inst *inst_cream = (mcr_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + unsigned int inst = inst_cream->inst; + if (inst_cream->Rd == 15) { + DEBUG_MSG; + } else { + if (inst_cream->cp_num == 15) { + if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { + //LET(RD, CONST(0x0007b000)); + //LET(RD, CONST(0x410FB760)); + //LET(CP15_MAIN_ID, R(RD)); + CP15_REG(CP15_MAIN_ID) = RD; + } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { + //LET(RD, R(CP15_CONTROL)); + CP15_REG(CP15_AUXILIARY_CONTROL) = RD; + } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { + //LET(RD, R(CP15_CONTROL)); + CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD; + } else if(CRn == 1 && CRm == 0 && OPCODE_2 == 0) { + //LET(CP15_CONTROL, R(RD)); + CP15_REG(CP15_CONTROL) = RD; + } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { + //LET(CP15_DOMAIN_ACCESS_CONTROL, R(RD)); + CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD; + } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { + //LET(CP15_TRANSLATION_BASE_TABLE_0, R(RD)); + CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD; + } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) { + //LET(CP15_TRANSLATION_BASE_TABLE_1, R(RD)); + CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD; + } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) { + //LET(CP15_TRANSLATION_BASE_CONTROL, R(RD)); + CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD; + } else if(CRn == MMU_CACHE_OPS){ + //SKYEYE_WARNING("cache operation have not implemented.\n"); + } else if(CRn == MMU_TLB_OPS){ + switch (CRm) { + case 5: /* ITLB */ + switch(OPCODE_2){ + case 0: /* invalidate all */ + //invalidate_all_tlb(state); + DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate all\n"); + //remove_tlb(INSN_TLB); + //erase_all(core, INSN_TLB); + break; + case 1: /* invalidate by MVA */ + //invalidate_by_mva(state, value); + //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by mva\n"); + //remove_tlb_by_mva(RD, INSN_TLB); + //erase_by_mva(core, RD, INSN_TLB); + break; + case 2: /* invalidate by asid */ + //invalidate_by_asid(state, value); + //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by asid\n"); + //erase_by_asid(core, RD, INSN_TLB); + break; + default: + break; + } + + break; + case 6: /* DTLB */ + switch(OPCODE_2){ + case 0: /* invalidate all */ + //invalidate_all_tlb(state); + //remove_tlb(DATA_TLB); + //erase_all(core, DATA_TLB); + DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate all\n"); + break; + case 1: /* invalidate by MVA */ + //invalidate_by_mva(state, value); + //remove_tlb_by_mva(RD, DATA_TLB); + //erase_by_mva(core, RD, DATA_TLB); + //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by mva\n"); + break; + case 2: /* invalidate by asid */ + //invalidate_by_asid(state, value); + //remove_tlb_by_asid(RD, DATA_TLB); + //erase_by_asid(core, RD, DATA_TLB); + //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by asid\n"); + break; + default: + break; + } + break; + case 7: /* UNIFILED TLB */ + switch(OPCODE_2){ + case 0: /* invalidate all */ + //invalidate_all_tlb(state); + //erase_all(core, INSN_TLB); + //erase_all(core, DATA_TLB); + //remove_tlb(DATA_TLB); + //remove_tlb(INSN_TLB); + //DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate all\n"); + break; + case 1: /* invalidate by MVA */ + //invalidate_by_mva(state, value); + //erase_by_mva(core, RD, DATA_TLB); + //erase_by_mva(core, RD, INSN_TLB); + DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by mva\n"); + break; + case 2: /* invalidate by asid */ + //invalidate_by_asid(state, value); + //erase_by_asid(core, RD, DATA_TLB); + //erase_by_asid(core, RD, INSN_TLB); + DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by asid\n"); + break; + default: + break; + } + break; + default: + break; + } + } else if(CRn == MMU_PID){ + if(OPCODE_2 == 0) + CP15_REG(CP15_PID) = RD; + else if(OPCODE_2 == 1) + CP15_REG(CP15_CONTEXT_ID) = RD; + else if(OPCODE_2 == 3){ + CP15_REG(CP15_THREAD_URO) = RD; + } + else{ + printf ("mmu_mcr wrote UNKNOWN - reg %d\n", CRn); + } + + } else { + DEBUG_LOG(ARM11, "mcr is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); + } + } + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(mcr_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + MCRR_INST: + MLA_INST: + { + INC_ICOUNTER; + mla_inst *inst_cream = (mla_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + uint64_t rm = RM; + uint64_t rs = RS; + uint64_t rn = RN; + if (inst_cream->Rm == 15 || inst_cream->Rs == 15 || inst_cream->Rn == 15) { + DEBUG_LOG(ARM11, "in __line__\n", __LINE__); + CITRA_IGNORE_EXIT(-1); + } +// RD = dst = RM * RS + RN; + RD = dst = static_cast<uint32_t>((rm * rs + rn) & 0xffffffff); + if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(mla_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(mla_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + MOV_INST: + { +// DEBUG_LOG(ARM11, "mov inst\n"); +// DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]); +// debug_function(cpu); +// cpu->icount ++; + INC_ICOUNTER; + mov_inst *inst_cream = (mov_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + RD = dst = SHIFTER_OPERAND; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr */ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_WITH_SC; + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(mov_inst)); + goto DISPATCH; + } +// return; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(mov_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + MRC_INST: + { + INC_ICOUNTER; + /* NOT IMPL */ + mrc_inst *inst_cream = (mrc_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + unsigned int inst = inst_cream->inst; + if (inst_cream->Rd == 15) { + DEBUG_MSG; + } + if (inst_cream->inst == 0xeef04a10) { + /* undefined instruction fmrx */ + RD = 0x20000000; + CITRA_IGNORE_EXIT(-1); + goto END; + } else { + if (inst_cream->cp_num == 15) { + if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { + //LET(RD, CONST(0x0007b000)); + //LET(RD, CONST(0x410FB760)); + //LET(RD, R(CP15_MAIN_ID)); + RD = cpu->CP15[CP15(CP15_MAIN_ID)]; + } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) { + //LET(RD, R(CP15_CONTROL)); + RD = cpu->CP15[CP15(CP15_CONTROL)]; + } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { + //LET(RD, R(CP15_CONTROL)); + RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)]; + } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { + //LET(RD, R(CP15_CONTROL)); + RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)]; + } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { + //LET(RD, R(CP15_DOMAIN_ACCESS_CONTROL)); + RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)]; + } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { + //LET(RD, R(CP15_TRANSLATION_BASE_TABLE_0)); + RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)]; + } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) { + //LET(RD, R(CP15_FAULT_STATUS)); + RD = cpu->CP15[CP15(CP15_FAULT_STATUS)]; + } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) { + //LET(RD, R(CP15_FAULT_ADDRESS)); + RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)]; + } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) { + //LET(RD, R(CP15_CACHE_TYPE)); + RD = cpu->CP15[CP15(CP15_CACHE_TYPE)]; + } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) { + //LET(RD, R(CP15_INSTR_FAULT_STATUS)); + RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)]; + } else if (CRn == 13) { + if(OPCODE_2 == 0) + RD = CP15_REG(CP15_PID); + else if(OPCODE_2 == 1) + RD = CP15_REG(CP15_CONTEXT_ID); + else if(OPCODE_2 == 3){ + RD = Memory::KERNEL_MEMORY_VADDR; + } + else{ + printf ("mmu_mrr wrote UNKNOWN - reg %d\n", CRn); + } + } + else { + DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); + } + } + //DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(mrc_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + MRRC_INST: + MRS_INST: + { + INC_ICOUNTER; + mrs_inst *inst_cream = (mrs_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (inst_cream->R) { + RD = cpu->Spsr_copy; + } else { + SAVE_NZCVT; + RD = cpu->Cpsr; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(mrs_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + MSR_INST: + { + INC_ICOUNTER; + msr_inst *inst_cream = (msr_inst *)inst_base->component; + const uint32_t UnallocMask = 0x06f0fc00, UserMask = 0xf80f0200, PrivMask = 0x000001df, StateMask = 0x01000020; + unsigned int inst = inst_cream->inst; + unsigned int operand; + + if (BIT(inst, 25)) { + int rot_imm = BITS(inst, 8, 11) * 2; + //operand = ROTL(CONST(BITS(0, 7)), CONST(32 - rot_imm)); + operand = ROTATE_RIGHT_32(BITS(inst, 0, 7), rot_imm); + } else { + //operand = R(RM); + operand = cpu->Reg[BITS(inst, 0, 3)]; + } + uint32_t byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0) + | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0); + uint32_t mask; + if (!inst_cream->R) { + if (InAPrivilegedMode(cpu)) { + if ((operand & StateMask) != 0) { + /* UNPREDICTABLE */ + DEBUG_MSG; + } else + mask = byte_mask & (UserMask | PrivMask); + } else { + mask = byte_mask & UserMask; + } + //LET(CPSR_REG, OR(AND(R(CPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask)))); + SAVE_NZCVT; + + cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask); + switch_mode(cpu, cpu->Cpsr & 0x1f); + LOAD_NZCVT; + } else { + if (CurrentModeHasSPSR) { + mask = byte_mask & (UserMask | PrivMask | StateMask); + //LET(SPSR_REG, OR(AND(R(SPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask)))); + cpu->Spsr_copy = (cpu->Spsr_copy & ~mask) | (operand & mask); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(msr_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + MUL_INST: + { + INC_ICOUNTER; + mul_inst *inst_cream = (mul_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { +// RD = dst = SHIFTER_OPERAND; + uint64_t rm = RM; + uint64_t rs = RS; + RD = dst = static_cast<uint32_t>((rm * rs) & 0xffffffff); + if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(mul_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(mul_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + MVN_INST: + { + INC_ICOUNTER; + mvn_inst *inst_cream = (mvn_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { +// RD = dst = (SHIFTER_OPERAND ^ 0xffffffff); + RD = dst = ~SHIFTER_OPERAND; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr */ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_WITH_SC; + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(mvn_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(mvn_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + ORR_INST: + { + INC_ICOUNTER; + orr_inst *inst_cream = (orr_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + lop = RN; + rop = SHIFTER_OPERAND; +// DEBUG_LOG(ARM11, "lop is %x, rop is %x, r2 is %x, r3 is %x\n", lop, rop, cpu->Reg[2], cpu->Reg[3]); + RD = dst = lop | rop; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr*/ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_WITH_SC; +// UPDATE_CFLAG(dst, lop, rop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(orr_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(orr_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + PKHBT_INST: + PKHTB_INST: + PLD_INST: + { + INC_ICOUNTER; + /* NOT IMPL */ + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(stc_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + QADD_INST: + QADD16_INST: + QADD8_INST: + QADDSUBX_INST: + QDADD_INST: + QDSUB_INST: + QSUB_INST: + QSUB16_INST: + QSUB8_INST: + QSUBADDX_INST: + REV_INST: + { + INC_ICOUNTER; + rev_inst *inst_cream = (rev_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + RD = ((RM & 0xff) << 24) | + (((RM >> 8) & 0xff) << 16) | + (((RM >> 16) & 0xff) << 8) | + ((RM >> 24) & 0xff); + if (inst_cream->Rm == 15) { + DEBUG_LOG(ARM11, "in line %d\n", __LINE__); + CITRA_IGNORE_EXIT(-1); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(rev_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + REV16_INST: + { + INC_ICOUNTER; + rev_inst *inst_cream = (rev_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + RD = (BITS(RM, 0, 7) << 8) | + BITS(RM, 8, 15) | + (BITS(RM, 16, 23) << 24) | + (BITS(RM, 24, 31) << 16); + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(rev_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + REVSH_INST: + RFE_INST: + RSB_INST: + { + INC_ICOUNTER; + rsb_inst *inst_cream = (rsb_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + rop = RN; + lop = SHIFTER_OPERAND; + if (inst_cream->Rn == 15) { + rop += 2 * GET_INST_SIZE(cpu);; + } + RD = dst = lop - rop; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr */ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); +// UPDATE_VFLAG((int)dst, (int)lop, (int)rop); + UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(rsb_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(rsb_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + RSC_INST: + { + INC_ICOUNTER; + rsc_inst *inst_cream = (rsc_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + //lop = RN + !cpu->CFlag; + //rop = SHIFTER_OPERAND; + //RD = dst = rop - lop; + lop = RN; + rop = SHIFTER_OPERAND; + RD = dst = rop - lop - !cpu->CFlag; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr */ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); +// UPDATE_CFLAG(dst, lop, rop); +// UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop); + UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(rop, lop, !cpu->CFlag); +// cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst))); + UPDATE_VFLAG_OVERFLOW_FROM((int)dst, (int)rop, (int)lop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(rsc_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(rsc_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SADD16_INST: + SADD8_INST: + SADDSUBX_INST: + SBC_INST: + { + INC_ICOUNTER; + sbc_inst *inst_cream = (sbc_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + lop = SHIFTER_OPERAND + !cpu->CFlag; + rop = RN; + RD = dst = rop - lop; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr */ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); +// UPDATE_CFLAG(dst, lop, rop); + //UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop); + //rop = rop - !cpu->CFlag; + if(rop >= !cpu->CFlag) + UPDATE_CFLAG_NOT_BORROW_FROM(rop - !cpu->CFlag, SHIFTER_OPERAND); + else + UPDATE_CFLAG_NOT_BORROW_FROM(rop, !cpu->CFlag); +// cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst))); + UPDATE_VFLAG_OVERFLOW_FROM(dst, rop, lop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(sbc_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(sbc_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SEL_INST: + SETEND_INST: + SHADD16_INST: + SHADD8_INST: + SHADDSUBX_INST: + SHSUB16_INST: + SHSUB8_INST: + SHSUBADDX_INST: + SMLA_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + smla_inst *inst_cream = (smla_inst *)inst_base->component; + int32_t operand1, operand2; + if (inst_cream->x == 0) + operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15); + else + operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31); + + if (inst_cream->y == 0) + operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); + else + operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); + RD = operand1 * operand2 + RN; + //FIXME: UPDATE Q FLAGS + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(smla_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SMLAD_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + smlad_inst *inst_cream = (smlad_inst *)inst_base->component; + long long int rm = cpu->Reg[inst_cream->Rm]; + long long int rn = cpu->Reg[inst_cream->Rn]; + long long int ra = cpu->Reg[inst_cream->Ra]; + /* see SMUAD */ + if(inst_cream->Ra == 15) + CITRA_IGNORE_EXIT(-1); + int operand2 = (inst_cream->m)? ROTATE_RIGHT_32(rm, 16):rm; + + int half_rn, half_operand2; + half_rn = rn & 0xFFFF; + half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn; + + half_operand2 = operand2 & 0xFFFF; + half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2; + + long long int product1 = half_rn * half_operand2; + + half_rn = (rn & 0xFFFF0000) >> 16; + half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn; + + half_operand2 = (operand2 & 0xFFFF0000) >> 16; + half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2; + + long long int product2 = half_rn * half_operand2; + + long long int signed_ra = (ra & 0x80000000)? (0xFFFFFFFF00000000LL) | ra : ra; + long long int result = product1 + product2 + signed_ra; + cpu->Reg[inst_cream->Rd] = result & 0xFFFFFFFF; + /* FIXME , should check Signed overflow */ + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(umlal_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + + SMLAL_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + umlal_inst *inst_cream = (umlal_inst *)inst_base->component; + long long int rm = RM; + long long int rs = RS; + if (BIT(rm, 31)) { + rm |= 0xffffffff00000000LL; + } + if (BIT(rs, 31)) { + rs |= 0xffffffff00000000LL; + } + long long int rst = rm * rs; + long long int rdhi32 = RDHI; + long long int hilo = (rdhi32 << 32) + RDLO; + rst += hilo; + RDLO = BITS(rst, 0, 31); + RDHI = BITS(rst, 32, 63); + if (inst_cream->S) { + cpu->NFlag = BIT(RDHI, 31); + cpu->ZFlag = (RDHI == 0 && RDLO == 0); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(umlal_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SMLALXY_INST: + SMLALD_INST: + SMLAW_INST: + SMLSD_INST: + SMLSLD_INST: + SMMLA_INST: + SMMLS_INST: + SMMUL_INST: + SMUAD_INST: + SMUL_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + smul_inst *inst_cream = (smul_inst *)inst_base->component; + uint32_t operand1, operand2; + if (inst_cream->x == 0) + operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15); + else + operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31); + + if (inst_cream->y == 0) + operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); + else + operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); + RD = operand1 * operand2; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(smul_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SMULL_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + umull_inst *inst_cream = (umull_inst *)inst_base->component; +// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); + int64_t rm = RM; + int64_t rs = RS; + if (BIT(rm, 31)) { + rm |= 0xffffffff00000000LL; + } + if (BIT(rs, 31)) { + rs |= 0xffffffff00000000LL; + } + int64_t rst = rm * rs; + RDHI = BITS(rst, 32, 63); + RDLO = BITS(rst, 0, 31); + + + if (inst_cream->S) { + cpu->NFlag = BIT(RDHI, 31); + cpu->ZFlag = (RDHI == 0 && RDLO == 0); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(umull_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SMULW_INST: + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + smlad_inst *inst_cream = (smlad_inst *)inst_base->component; +// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); + int64_t rm = RM; + int64_t rn = RN; + if (inst_cream->m) + rm = BITS(rm,16 , 31); + else + rm = BITS(rm,0 , 15); + int64_t rst = rm * rn; + RD = BITS(rst, 16, 47); + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(smlad_inst)); + FETCH_INST; + GOTO_NEXT_INST; + + SMUSD_INST: + SRS_INST: + SSAT_INST: + SSAT16_INST: + SSUB16_INST: + SSUB8_INST: + SSUBADDX_INST: + STC_INST: + { + INC_ICOUNTER; + /* NOT IMPL */ + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(stc_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STM_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + unsigned int inst = inst_cream->inst; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + int i; + unsigned int Rn = BITS(inst, 16, 19); + unsigned int old_RN = cpu->Reg[Rn]; + + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + if (BIT(inst_cream->inst, 22) == 1) { +// DEBUG_MSG; + #if 1 + for (i = 0; i < 13; i++) { + if(BIT(inst_cream->inst, i)){ + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) { + goto MMU_EXCEPTION; + } + fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); + if (fault) goto MMU_EXCEPTION; + addr += 4; + phys_addr += 4; + } + } + if (BIT(inst_cream->inst, 13)) { + if (cpu->Mode == USER32MODE) { + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) { + goto MMU_EXCEPTION; + } + fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); + if (fault) goto MMU_EXCEPTION; + addr += 4; + phys_addr += 4; + } else { + fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[0], 32); + if (fault) goto MMU_EXCEPTION; + addr += 4; + phys_addr += 4; + } + } + if (BIT(inst_cream->inst, 14)) { + if (cpu->Mode == USER32MODE) { + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) { + goto MMU_EXCEPTION; + } + fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); + if (fault) goto MMU_EXCEPTION; + addr += 4; + phys_addr += 4; + } else { + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) { + goto MMU_EXCEPTION; + } + fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[1], 32); + if (fault) goto MMU_EXCEPTION; + addr += 4; + phys_addr += 4; + } + } + if (BIT(inst_cream->inst, 15)) { + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) { + goto MMU_EXCEPTION; + } + fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32); + if (fault) goto MMU_EXCEPTION; + } + #endif + } else { + for( i = 0; i < 15; i ++ ){ + if(BIT(inst_cream->inst, i)){ + //arch_write_memory(cpu, bb, Addr, R(i), 32); + //bus_write(32, addr, cpu->Reg[i]); + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) { + goto MMU_EXCEPTION; + } + if(i == Rn) + fault = interpreter_write_memory(addr, phys_addr, old_RN, 32); + else + fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); + if (fault) goto MMU_EXCEPTION; + addr += 4; + phys_addr += 4; + //Addr = ADD(Addr, CONST(4)); + } + } + + /* check pc reg*/ + if(BIT(inst_cream->inst, i)){ + //arch_write_memory(cpu, bb, Addr, STOREM_CHECK_PC, 32); + //bus_write(32, addr, cpu->Reg[i] + 8); + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) { + goto MMU_EXCEPTION; + } + fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32); + if (fault) goto MMU_EXCEPTION; + } + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SXTB_INST: + { + INC_ICOUNTER; + sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (inst_cream->Rm == 15) { + DEBUG_LOG(ARM11, "line is %d\n", __LINE__); + CITRA_IGNORE_EXIT(-1); + } + unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate); + if (BIT(operand2, 7)) { + operand2 |= 0xffffff00; + } else + operand2 &= 0xff; + RD = operand2; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(sxtb_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STR_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; + //bus_write(32, addr, value); + fault = interpreter_write_memory(addr, phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + UXTB_INST: + { + INC_ICOUNTER; + uxtb_inst *inst_cream = (uxtb_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) + & 0xff; + RD = operand2; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(uxtb_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + UXTAB_INST: + { + INC_ICOUNTER; + uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) + & 0xff; + RD = RN + operand2; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(uxtab_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STRB_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; + //bus_write(8, addr, value); + fault = interpreter_write_memory(addr, phys_addr, value, 8); + if (fault) goto MMU_EXCEPTION; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STRBT_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; + //bus_write(8, addr, value); + fault = interpreter_write_memory(addr, phys_addr, value, 8); + if (fault) goto MMU_EXCEPTION; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + //if (BITS(inst_cream->inst, 12, 15) == 15) + // goto DISPATCH; + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STRD_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + uint32_t rear_phys_addr; + fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 0); + if (fault){ + ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n"); + CITRA_IGNORE_EXIT(-1); + goto MMU_EXCEPTION; + } + + //fault = inst_cream->get_addr(cpu, inst_cream->inst, addr + 4, phys_addr + 4, 0); + //if (fault) goto MMU_EXCEPTION; + + unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; + //bus_write(32, addr, value); + fault = interpreter_write_memory(addr, phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + value = cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]; + //bus_write(32, addr, value); + fault = interpreter_write_memory(addr + 4, rear_phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STREX_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; + unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)]; + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + + int dest_reg = BITS(inst_cream->inst, 12, 15); + if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){ + remove_exclusive(cpu, phys_addr); + cpu->Reg[dest_reg] = 0; + cpu->exclusive_state = 0; + + // bus_write(32, addr, value); + fault = interpreter_write_memory(addr, phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + } + else{ + /* Failed to write due to mutex access */ + cpu->Reg[dest_reg] = 1; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STREXB_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; + unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)] & 0xff; + fault = check_address_validity(cpu, addr, &phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + //bus_write(8, addr, value); + int dest_reg = BITS(inst_cream->inst, 12, 15); + if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){ + remove_exclusive(cpu, phys_addr); + cpu->Reg[dest_reg] = 0; + cpu->exclusive_state = 0; + fault = interpreter_write_memory(addr, phys_addr, value, 8); + if (fault) goto MMU_EXCEPTION; + + } + else{ + cpu->Reg[dest_reg] = 1; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STRH_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff; + //bus_write(16, addr, value); + fault = interpreter_write_memory(addr, phys_addr, value, 16); + if (fault) goto MMU_EXCEPTION; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + //if (BITS(inst_cream->inst, 12, 15) == 15) + // goto DISPATCH; + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + STRT_INST: + { + INC_ICOUNTER; + ldst_inst *inst_cream = (ldst_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); + if (fault) goto MMU_EXCEPTION; + unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; + //bus_write(16, addr, value); + fault = interpreter_write_memory(addr, phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(ldst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SUB_INST: + { + INC_ICOUNTER; + sub_inst *inst_cream = (sub_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + lop = RN; + if (inst_cream->Rn == 15) { + lop += 8; + } + rop = SHIFTER_OPERAND; + RD = dst = lop - rop; + if (inst_cream->S && (inst_cream->Rd == 15)) { + /* cpsr = spsr */ + if (CurrentModeHasSPSR) { + cpu->Cpsr = cpu->Spsr_copy; + switch_mode(cpu, cpu->Spsr_copy & 0x1f); + LOAD_NZCVT; + } + } else if (inst_cream->S) { + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); +// UPDATE_CFLAG(dst, lop, rop); + UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); + // UPDATE_VFLAG((int)dst, (int)lop, (int)rop); + UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); + } + if (inst_cream->Rd == 15) { + INC_PC(sizeof(sub_inst)); + goto DISPATCH; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(sub_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SWI_INST: + { + INC_ICOUNTER; + swi_inst *inst_cream = (swi_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (true){ //if (core->is_user_mode) { --> Citra only emulates user mode + //arm_dyncom_SWI(cpu, inst_cream->num); + HLE::CallSVC(Memory::Read32(cpu->Reg[15])); + } else { + cpu->syscallSig = 1; + goto END; + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(swi_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SWP_INST: + { + INC_ICOUNTER; + swp_inst *inst_cream = (swp_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + addr = RN; + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 32); + if (fault) goto MMU_EXCEPTION; + fault = interpreter_write_memory(addr, phys_addr, RM, 32); + if (fault) goto MMU_EXCEPTION; + + /* ROR(data, 8*UInt(address<1:0>)); */ + assert((phys_addr & 0x3) == 0); + RD = value; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(swp_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SWPB_INST: + { + INC_ICOUNTER; + swp_inst *inst_cream = (swp_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + addr = RN; + fault = check_address_validity(cpu, addr, &phys_addr, 1); + if (fault) goto MMU_EXCEPTION; + unsigned int value; + fault = interpreter_read_memory(addr, phys_addr, value, 8); + if (fault) goto MMU_EXCEPTION; + fault = interpreter_write_memory(addr, phys_addr, (RM & 0xFF), 8); + if (fault) goto MMU_EXCEPTION; + + /* FIXME */ + #if 0 + if Shared(address) then + /* ARMv6 */ + physical_address = TLB(address) + ClearExclusiveByAddress(physical_address,processor_id,1) + /* See Summary of operation on page A2-49 */ + #endif + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(swp_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SXTAB_INST: + { + INC_ICOUNTER; + sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + /* R15 should be check */ + if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){ + CITRA_IGNORE_EXIT(-1); + } + unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) + & 0xff; + /* sign extend for byte */ + operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2; + RD = RN + operand2; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(uxtab_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SXTAB16_INST: + SXTAH_INST: + { + INC_ICOUNTER; + sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + /* R15 should be check */ + if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){ + CITRA_IGNORE_EXIT(-1); + } + unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; + /* sign extend for half */ + operand2 = (0x8000 & operand2)? (0xFFFF0000 | operand2):operand2; + RD = RN + operand2; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(sxtah_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + SXTB16_INST: + TEQ_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + teq_inst *inst_cream = (teq_inst *)inst_base->component; + lop = RN; + if (inst_cream->Rn == 15) + lop += GET_INST_SIZE(cpu) * 2; + + rop = SHIFTER_OPERAND; + dst = lop ^ rop; + + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_WITH_SC; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(teq_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + TST_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + tst_inst *inst_cream = (tst_inst *)inst_base->component; + lop = RN; + if (inst_cream->Rn == 15) + lop += GET_INST_SIZE(cpu) * 2; + rop = SHIFTER_OPERAND; + dst = lop & rop; + + UPDATE_NFLAG(dst); + UPDATE_ZFLAG(dst); + UPDATE_CFLAG_WITH_SC; + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(tst_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + UADD16_INST: + UADD8_INST: + UADDSUBX_INST: + UHADD16_INST: + UHADD8_INST: + UHADDSUBX_INST: + UHSUB16_INST: + UHSUB8_INST: + UHSUBADDX_INST: + UMAAL_INST: + UMLAL_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + umlal_inst *inst_cream = (umlal_inst *)inst_base->component; + unsigned long long int rm = RM; + unsigned long long int rs = RS; + unsigned long long int rst = rm * rs; + unsigned long long int add = ((unsigned long long) RDHI)<<32; + add += RDLO; + //DEBUG_LOG(ARM11, "rm[%llx] * rs[%llx] = rst[%llx] | add[%llx]\n", RM, RS, rst, add); + rst += add; + RDLO = BITS(rst, 0, 31); + RDHI = BITS(rst, 32, 63); + + if (inst_cream->S) + { + cpu->NFlag = BIT(RDHI, 31); + cpu->ZFlag = (RDHI == 0 && RDLO == 0); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(umlal_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + UMULL_INST: + { + INC_ICOUNTER; + if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + umull_inst *inst_cream = (umull_inst *)inst_base->component; + unsigned long long int rm = RM; + unsigned long long int rs = RS; + unsigned long long int rst = rm * rs; +// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); + RDHI = BITS(rst, 32, 63); + RDLO = BITS(rst, 0, 31); + + if (inst_cream->S) { + cpu->NFlag = BIT(RDHI, 31); + cpu->ZFlag = (RDHI == 0 && RDLO == 0); + } + } + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(umull_inst)); + FETCH_INST; + GOTO_NEXT_INST; + } + B_2_THUMB: + { + INC_ICOUNTER; + b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; + cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; + //DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); + INC_PC(sizeof(b_2_thumb)); + goto DISPATCH; + } + B_COND_THUMB: + { + INC_ICOUNTER; + b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; + if(CondPassed(cpu, inst_cream->cond)) + cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; + else + cpu->Reg[15] += 2; + //DEBUG_LOG(ARM11, " B_COND_THUMB: imm=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[15]); + INC_PC(sizeof(b_cond_thumb)); + goto DISPATCH; + } + BL_1_THUMB: + { + INC_ICOUNTER; + bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; + cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm; + //cpu->Reg[15] += 2; + //DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); + + cpu->Reg[15] += GET_INST_SIZE(cpu); + INC_PC(sizeof(bl_1_thumb)); + FETCH_INST; + GOTO_NEXT_INST; + + } + BL_2_THUMB: + { + INC_ICOUNTER; + bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; + int tmp = ((cpu->Reg[15] + 2) | 1); + cpu->Reg[15] = + (cpu->Reg[14] + inst_cream->imm); + cpu->Reg[14] = tmp; + //DEBUG_LOG(ARM11, " BL_2_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); + INC_PC(sizeof(bl_2_thumb)); + goto DISPATCH; + } + BLX_1_THUMB: + { + /* BLX 1 for armv5t and above */ + INC_ICOUNTER; + uint32 tmp = cpu->Reg[15]; + blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component; + cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm) & 0xFFFFFFFC; + //DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, instr=0x%x\n", inst_cream->imm, cpu->Reg[14], inst_cream->instr); + cpu->Reg[14] = ((tmp + 2) | 1); + //(state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC; + /* switch to arm state from thumb state */ + cpu->TFlag = 0; + //DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, r15=0x%x, \n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); + INC_PC(sizeof(blx_1_thumb)); + goto DISPATCH; + } + + UQADD16_INST: + UQADD8_INST: + UQADDSUBX_INST: + UQSUB16_INST: + UQSUB8_INST: + UQSUBADDX_INST: + USAD8_INST: + USADA8_INST: + USAT_INST: + USAT16_INST: + USUB16_INST: + USUB8_INST: + USUBADDX_INST: + UXTAB16_INST: + UXTB16_INST: + #define VFP_INTERPRETER_IMPL + #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" + #undef VFP_INTERPRETER_IMPL + MMU_EXCEPTION: + { + SAVE_NZCVT; + cpu->abortSig = true; + cpu->Aborted = ARMul_DataAbortV; + cpu->AbortAddr = addr; + cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff; + cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr; + cpu->NumInstrsToExecute = 0; + return num_instrs; + } + END: + { + SAVE_NZCVT; + cpu->NumInstrsToExecute = 0; + return num_instrs; + } + INIT_INST_LENGTH: + { +#if 0 + DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel)); + for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++) + DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]); + DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel)); +#endif +#if defined __GNUC__ || defined __clang__ + InterpreterInitInstLength((unsigned long long int *)InstLabel, sizeof(InstLabel)); +#endif +#if 0 + for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++) + DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]); + DEBUG_LOG(ARM11, "%llx\n", InstEndLabel[1]); + DEBUG_LOG(ARM11, "%llx\n", InstLabel[1]); + DEBUG_LOG(ARM11, "%lld\n", (char *)InstEndLabel[1] - (char *)InstLabel[1]); +#endif + cpu->NumInstrsToExecute = 0; + return num_instrs; + } +} + diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h new file mode 100644 index 000000000..c65eb23f7 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h @@ -0,0 +1,7 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +unsigned InterpreterMainLoop(ARMul_State* state); diff --git a/src/core/arm/dyncom/arm_dyncom_run.cpp b/src/core/arm/dyncom/arm_dyncom_run.cpp new file mode 100644 index 000000000..a2026cbf3 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_run.cpp @@ -0,0 +1,120 @@ +/* Copyright (C) +* 2011 - Michael.Kang blackfin.kang@gmail.com +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ +/** +* @file arm_dyncom_run.cpp +* @brief The dyncom run implementation for arm +* @author Michael.Kang blackfin.kang@gmail.com +* @version 78.77 +* @date 2011-11-20 +*/ + +#include <assert.h> + +#include "core/arm/skyeye_common/armdefs.h" + +void switch_mode(arm_core_t *core, uint32_t mode) +{ + uint32_t tmp1, tmp2; + if (core->Mode == mode) { + //Mode not changed. + //printf("mode not changed\n"); + return; + } + //printf("%d --->>> %d\n", core->Mode, mode); + //printf("In %s, Cpsr=0x%x, R15=0x%x, last_pc=0x%x, cpsr=0x%x, spsr_copy=0x%x, icounter=%lld\n", __FUNCTION__, core->Cpsr, core->Reg[15], core->last_pc, core->Cpsr, core->Spsr_copy, core->icounter); + if (mode != USERBANK) { + switch (core->Mode) { + case USER32MODE: + core->Reg_usr[0] = core->Reg[13]; + core->Reg_usr[1] = core->Reg[14]; + break; + case IRQ32MODE: + core->Reg_irq[0] = core->Reg[13]; + core->Reg_irq[1] = core->Reg[14]; + core->Spsr[IRQBANK] = core->Spsr_copy; + break; + case SVC32MODE: + core->Reg_svc[0] = core->Reg[13]; + core->Reg_svc[1] = core->Reg[14]; + core->Spsr[SVCBANK] = core->Spsr_copy; + break; + case ABORT32MODE: + core->Reg_abort[0] = core->Reg[13]; + core->Reg_abort[1] = core->Reg[14]; + core->Spsr[ABORTBANK] = core->Spsr_copy; + break; + case UNDEF32MODE: + core->Reg_undef[0] = core->Reg[13]; + core->Reg_undef[1] = core->Reg[14]; + core->Spsr[UNDEFBANK] = core->Spsr_copy; + break; + case FIQ32MODE: + core->Reg_firq[0] = core->Reg[13]; + core->Reg_firq[1] = core->Reg[14]; + core->Spsr[FIQBANK] = core->Spsr_copy; + break; + + } + + switch (mode) { + case USER32MODE: + core->Reg[13] = core->Reg_usr[0]; + core->Reg[14] = core->Reg_usr[1]; + core->Bank = USERBANK; + break; + case IRQ32MODE: + core->Reg[13] = core->Reg_irq[0]; + core->Reg[14] = core->Reg_irq[1]; + core->Spsr_copy = core->Spsr[IRQBANK]; + core->Bank = IRQBANK; + break; + case SVC32MODE: + core->Reg[13] = core->Reg_svc[0]; + core->Reg[14] = core->Reg_svc[1]; + core->Spsr_copy = core->Spsr[SVCBANK]; + core->Bank = SVCBANK; + break; + case ABORT32MODE: + core->Reg[13] = core->Reg_abort[0]; + core->Reg[14] = core->Reg_abort[1]; + core->Spsr_copy = core->Spsr[ABORTBANK]; + core->Bank = ABORTBANK; + break; + case UNDEF32MODE: + core->Reg[13] = core->Reg_undef[0]; + core->Reg[14] = core->Reg_undef[1]; + core->Spsr_copy = core->Spsr[UNDEFBANK]; + core->Bank = UNDEFBANK; + break; + case FIQ32MODE: + core->Reg[13] = core->Reg_firq[0]; + core->Reg[14] = core->Reg_firq[1]; + core->Spsr_copy = core->Spsr[FIQBANK]; + core->Bank = FIQBANK; + break; + + } + core->Mode = mode; + //printf("In %si end, Cpsr=0x%x, R15=0x%x, last_pc=0x%x, cpsr=0x%x, spsr_copy=0x%x, icounter=%lld\n", __FUNCTION__, core->Cpsr, core->Reg[15], core->last_pc, core->Cpsr, core->Spsr_copy, core->icounter); + //printf("\n--------------------------------------\n"); + } + else { + printf("user mode\n"); + exit(-2); + } +} diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h new file mode 100644 index 000000000..aeabeac16 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_run.h @@ -0,0 +1,55 @@ +/* Copyright (C) +* 2011 - Michael.Kang blackfin.kang@gmail.com +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ + +#ifndef __ARM_DYNCOM_RUN__ +#define __ARM_DYNCOM_RUN__ + +#include "core/arm/skyeye_common/skyeye_types.h" + +void switch_mode(arm_core_t *core, uint32_t mode); + +/* FIXME, we temporarily think thumb instruction is always 16 bit */ +static inline uint32 GET_INST_SIZE(arm_core_t* core){ + return core->TFlag? 2 : 4; +} + +/** +* @brief Read R15 and forced R15 to wold align, used address calculation +* +* @param core +* @param Rn +* +* @return +*/ +static inline addr_t CHECK_READ_REG15_WA(arm_core_t* core, int Rn){ + return (Rn == 15)? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; +} + +/** +* @brief Read R15, used to data processing with pc +* +* @param core +* @param Rn +* +* @return +*/ +static inline uint32 CHECK_READ_REG15(arm_core_t* core, int Rn){ + return (Rn == 15)? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; +} + +#endif diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp new file mode 100644 index 000000000..e10f2f9ee --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp @@ -0,0 +1,521 @@ +/* Copyright (C) +* 2011 - Michael.Kang blackfin.kang@gmail.com +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ +/** +* @file arm_dyncom_thumb.c +* @brief The thumb dynamic interpreter +* @author Michael.Kang blackfin.kang@gmail.com +* @version 78.77 +* @date 2011-11-07 +*/ + +/* We can provide simple Thumb simulation by decoding the Thumb +instruction into its corresponding ARM instruction, and using the +existing ARM simulator. */ + +#include "core/arm/skyeye_common/skyeye_defs.h" + +#ifndef MODET /* required for the Thumb instruction support */ +#if 1 +#error "MODET needs to be defined for the Thumb world to work" +#else +#define MODET (1) +#endif +#endif + +#include "core/arm/skyeye_common/armos.h" +#include "core/arm/dyncom/arm_dyncom_thumb.h" + +/* Decode a 16bit Thumb instruction. The instruction is in the low + 16-bits of the tinstr field, with the following Thumb instruction + held in the high 16-bits. Passing in two Thumb instructions allows + easier simulation of the special dual BL instruction. */ + +tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size) +{ + tdstate valid = t_uninitialized; + ARMword next_instr; + ARMword tinstr; + tinstr = instr; + /* The endian should be judge here */ + #if 0 + if (state->bigendSig) { + next_instr = tinstr & 0xFFFF; + tinstr >>= 16; + } + else { + next_instr = tinstr >> 16; + tinstr &= 0xFFFF; + } + #endif + if((addr & 0x3) != 0) + tinstr = instr >> 16; + else + tinstr &= 0xFFFF; + + //printf("In %s, instr=0x%x, tinstr=0x%x, r15=0x%x\n", __FUNCTION__, instr, tinstr, cpu->translate_pc); +#if 1 /* debugging to catch non updates */ + *ainstr = 0xDEADC0DE; +#endif + + switch ((tinstr & 0xF800) >> 11) { + case 0: /* LSL */ + case 1: /* LSR */ + case 2: /* ASR */ + /* Format 1 */ + *ainstr = 0xE1B00000 /* base opcode */ + | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */ + |((tinstr & 0x07C0) << (7 - 6)) /* imm5 */ + |((tinstr & 0x0038) >> 3) /* Rs */ + |((tinstr & 0x0007) << 12); /* Rd */ + break; + case 3: /* ADD/SUB */ + /* Format 2 */ + { + ARMword subset[4] = { + 0xE0900000, /* ADDS Rd,Rs,Rn */ + 0xE0500000, /* SUBS Rd,Rs,Rn */ + 0xE2900000, /* ADDS Rd,Rs,#imm3 */ + 0xE2500000 /* SUBS Rd,Rs,#imm3 */ + }; + /* It is quicker indexing into a table, than performing switch + or conditionals: */ + *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */ + |((tinstr & 0x01C0) >> 6) /* Rn or imm3 */ + |((tinstr & 0x0038) << (16 - 3)) /* Rs */ + |((tinstr & 0x0007) << (12 - 0)); /* Rd */ + } + break; + case 4: /* MOV */ + case 5: /* CMP */ + case 6: /* ADD */ + case 7: /* SUB */ + /* Format 3 */ + { + ARMword subset[4] = { + 0xE3B00000, /* MOVS Rd,#imm8 */ + 0xE3500000, /* CMP Rd,#imm8 */ + 0xE2900000, /* ADDS Rd,Rd,#imm8 */ + 0xE2500000, /* SUBS Rd,Rd,#imm8 */ + }; + *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */ + |((tinstr & 0x00FF) >> 0) /* imm8 */ + |((tinstr & 0x0700) << (16 - 8)) /* Rn */ + |((tinstr & 0x0700) << (12 - 8)); /* Rd */ + } + break; + case 8: /* Arithmetic and high register transfers */ + /* TODO: Since the subsets for both Format 4 and Format 5 + instructions are made up of different ARM encodings, we could + save the following conditional, and just have one large + subset. */ + if ((tinstr & (1 << 10)) == 0) { + typedef enum + { t_norm, t_shift, t_neg, t_mul }otype_t; + + /* Format 4 */ + struct + { + ARMword opcode; + otype_t otype; + } + subset[16] = { + { + 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */ + { + 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */ + { + 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */ + { + 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */ + { + 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */ + { + 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */ + { + 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */ + { + 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */ + { + 0xE1100000, t_norm}, /* TST Rd,Rs */ + { + 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */ + { + 0xE1500000, t_norm}, /* CMP Rd,Rs */ + { + 0xE1700000, t_norm}, /* CMN Rd,Rs */ + { + 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */ + { + 0xE0100090, t_mul}, /* MULS Rd,Rd,Rs */ + { + 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */ + { + 0xE1F00000, t_norm} /* MVNS Rd,Rs */ + }; + *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */ + switch (subset[(tinstr & 0x03C0) >> 6].otype) { + case t_norm: + *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */ + |((tinstr & 0x0007) << 12) /* Rd */ + |((tinstr & 0x0038) >> 3); /* Rs */ + break; + case t_shift: + *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ + |((tinstr & 0x0007) >> 0) /* Rm */ + |((tinstr & 0x0038) << (8 - 3)); /* Rs */ + break; + case t_neg: + *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)); /* Rn */ + break; + case t_mul: + *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */ + |((tinstr & 0x0007) << 8) /* Rs */ + |((tinstr & 0x0038) >> 3); /* Rm */ + break; + } + } + else { + /* Format 5 */ + ARMword Rd = ((tinstr & 0x0007) >> 0); + ARMword Rs = ((tinstr & 0x0038) >> 3); + if (tinstr & (1 << 7)) + Rd += 8; + if (tinstr & (1 << 6)) + Rs += 8; + switch ((tinstr & 0x03C0) >> 6) { + case 0x1: /* ADD Rd,Rd,Hs */ + case 0x2: /* ADD Hd,Hd,Rs */ + case 0x3: /* ADD Hd,Hd,Hs */ + *ainstr = 0xE0800000 /* base */ + | (Rd << 16) /* Rn */ + |(Rd << 12) /* Rd */ + |(Rs << 0); /* Rm */ + break; + case 0x5: /* CMP Rd,Hs */ + case 0x6: /* CMP Hd,Rs */ + case 0x7: /* CMP Hd,Hs */ + *ainstr = 0xE1500000 /* base */ + | (Rd << 16) /* Rn */ + |(Rd << 12) /* Rd */ + |(Rs << 0); /* Rm */ + break; + case 0x9: /* MOV Rd,Hs */ + case 0xA: /* MOV Hd,Rs */ + case 0xB: /* MOV Hd,Hs */ + *ainstr = 0xE1A00000 /* base */ + | (Rd << 16) /* Rn */ + |(Rd << 12) /* Rd */ + |(Rs << 0); /* Rm */ + break; + case 0xC: /* BX Rs */ + case 0xD: /* BX Hs */ + *ainstr = 0xE12FFF10 /* base */ + | ((tinstr & 0x0078) >> 3); /* Rd */ + break; + case 0x0: /* UNDEFINED */ + case 0x4: /* UNDEFINED */ + case 0x8: /* UNDEFINED */ + valid = t_undefined; + break; + case 0xE: /* BLX */ + case 0xF: /* BLX */ + + //if (state->is_v5) { + if(1){ + //valid = t_branch; + #if 1 + *ainstr = 0xE1200030 /* base */ + |(Rs << 0); /* Rm */ + #endif + } else { + valid = t_undefined; + } + break; + } + } + break; + case 9: /* LDR Rd,[PC,#imm8] */ + /* Format 6 */ + *ainstr = 0xE59F0000 /* base */ + | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ + |((tinstr & 0x00FF) << (2 - 0)); /* off8 */ + break; + case 10: + case 11: + /* TODO: Format 7 and Format 8 perform the same ARM encoding, so + the following could be merged into a single subset, saving on + the following boolean: */ + if ((tinstr & (1 << 9)) == 0) { + /* Format 7 */ + ARMword subset[4] = { + 0xE7800000, /* STR Rd,[Rb,Ro] */ + 0xE7C00000, /* STRB Rd,[Rb,Ro] */ + 0xE7900000, /* LDR Rd,[Rb,Ro] */ + 0xE7D00000 /* LDRB Rd,[Rb,Ro] */ + }; + *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ + |((tinstr & 0x0007) << (12 - 0)) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)) /* Rb */ + |((tinstr & 0x01C0) >> 6); /* Ro */ + } + else { + /* Format 8 */ + ARMword subset[4] = { + 0xE18000B0, /* STRH Rd,[Rb,Ro] */ + 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */ + 0xE19000B0, /* LDRH Rd,[Rb,Ro] */ + 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */ + }; + *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */ + |((tinstr & 0x0007) << (12 - 0)) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)) /* Rb */ + |((tinstr & 0x01C0) >> 6); /* Ro */ + } + break; + case 12: /* STR Rd,[Rb,#imm5] */ + case 13: /* LDR Rd,[Rb,#imm5] */ + case 14: /* STRB Rd,[Rb,#imm5] */ + case 15: /* LDRB Rd,[Rb,#imm5] */ + /* Format 9 */ + { + ARMword subset[4] = { + 0xE5800000, /* STR Rd,[Rb,#imm5] */ + 0xE5900000, /* LDR Rd,[Rb,#imm5] */ + 0xE5C00000, /* STRB Rd,[Rb,#imm5] */ + 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */ + }; + /* The offset range defends on whether we are transferring a + byte or word value: */ + *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */ + |((tinstr & 0x0007) << (12 - 0)) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)) /* Rb */ + |((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */ + } + break; + case 16: /* STRH Rd,[Rb,#imm5] */ + case 17: /* LDRH Rd,[Rb,#imm5] */ + /* Format 10 */ + *ainstr = ((tinstr & (1 << 11)) /* base */ + ? 0xE1D000B0 /* LDRH */ + : 0xE1C000B0) /* STRH */ + |((tinstr & 0x0007) << (12 - 0)) /* Rd */ + |((tinstr & 0x0038) << (16 - 3)) /* Rb */ + |((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */ + |((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */ + break; + case 18: /* STR Rd,[SP,#imm8] */ + case 19: /* LDR Rd,[SP,#imm8] */ + /* Format 11 */ + *ainstr = ((tinstr & (1 << 11)) /* base */ + ? 0xE59D0000 /* LDR */ + : 0xE58D0000) /* STR */ + |((tinstr & 0x0700) << (12 - 8)) /* Rd */ + |((tinstr & 0x00FF) << 2); /* off8 */ + break; + case 20: /* ADD Rd,PC,#imm8 */ + case 21: /* ADD Rd,SP,#imm8 */ + /* Format 12 */ + if ((tinstr & (1 << 11)) == 0) { + /* NOTE: The PC value used here should by word aligned */ + /* We encode shift-left-by-2 in the rotate immediate field, + so no shift of off8 is needed. */ + *ainstr = 0xE28F0F00 /* base */ + | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ + |(tinstr & 0x00FF); /* off8 */ + } + else { + /* We encode shift-left-by-2 in the rotate immediate field, + so no shift of off8 is needed. */ + *ainstr = 0xE28D0F00 /* base */ + | ((tinstr & 0x0700) << (12 - 8)) /* Rd */ + |(tinstr & 0x00FF); /* off8 */ + } + break; + case 22: + case 23: + if ((tinstr & 0x0F00) == 0x0000) { + /* Format 13 */ + /* NOTE: The instruction contains a shift left of 2 + equivalent (implemented as ROR #30): */ + *ainstr = ((tinstr & (1 << 7)) /* base */ + ? 0xE24DDF00 /* SUB */ + : 0xE28DDF00) /* ADD */ + |(tinstr & 0x007F); /* off7 */ + } + else if ((tinstr & 0x0F00) == 0x0e00) + *ainstr = 0xEF000000 | SWI_Breakpoint; + else { + /* Format 14 */ + ARMword subset[4] = { + 0xE92D0000, /* STMDB sp!,{rlist} */ + 0xE92D4000, /* STMDB sp!,{rlist,lr} */ + 0xE8BD0000, /* LDMIA sp!,{rlist} */ + 0xE8BD8000 /* LDMIA sp!,{rlist,pc} */ + }; + *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] /* base */ + |(tinstr & 0x00FF); /* mask8 */ + } + break; + case 24: /* STMIA */ + case 25: /* LDMIA */ + /* Format 15 */ + *ainstr = ((tinstr & (1 << 11)) /* base */ + ? 0xE8B00000 /* LDMIA */ + : 0xE8A00000) /* STMIA */ + |((tinstr & 0x0700) << (16 - 8)) /* Rb */ + |(tinstr & 0x00FF); /* mask8 */ + break; + case 26: /* Bcc */ + case 27: /* Bcc/SWI */ + if ((tinstr & 0x0F00) == 0x0F00) { + #if 0 + if (tinstr == (ARMul_ABORTWORD & 0xffff) && + state->AbortAddr == pc) { + *ainstr = ARMul_ABORTWORD; + break; + } + #endif + /* Format 17 : SWI */ + *ainstr = 0xEF000000; + /* Breakpoint must be handled specially. */ + if ((tinstr & 0x00FF) == 0x18) + *ainstr |= ((tinstr & 0x00FF) << 16); + /* New breakpoint value. See gdb/arm-tdep.c */ + else if ((tinstr & 0x00FF) == 0xFE) + *ainstr |= SWI_Breakpoint; + else + *ainstr |= (tinstr & 0x00FF); + } + else if ((tinstr & 0x0F00) != 0x0E00) { + /* Format 16 */ + #if 0 + int doit = FALSE; + /* TODO: Since we are doing a switch here, we could just add + the SWI and undefined instruction checks into this + switch to same on a couple of conditionals: */ + switch ((tinstr & 0x0F00) >> 8) { + case EQ: + doit = ZFLAG; + break; + case NE: + doit = !ZFLAG; + break; + case VS: + doit = VFLAG; + break; + case VC: + doit = !VFLAG; + break; + case MI: + doit = NFLAG; + break; + case PL: + doit = !NFLAG; + break; + case CS: + doit = CFLAG; + break; + case CC: + doit = !CFLAG; + break; + case HI: + doit = (CFLAG && !ZFLAG); + break; + case LS: + doit = (!CFLAG || ZFLAG); + break; + case GE: + doit = ((!NFLAG && !VFLAG) + || (NFLAG && VFLAG)); + break; + case LT: + doit = ((NFLAG && !VFLAG) + || (!NFLAG && VFLAG)); + break; + case GT: + doit = ((!NFLAG && !VFLAG && !ZFLAG) + || (NFLAG && VFLAG && !ZFLAG)); + break; + case LE: + doit = ((NFLAG && !VFLAG) + || (!NFLAG && VFLAG)) || ZFLAG; + break; + } + if (doit) { + state->Reg[15] = (pc + 4 + + (((tinstr & 0x7F) << 1) + | ((tinstr & (1 << 7)) ? + 0xFFFFFF00 : 0))); + FLUSHPIPE; + } + #endif + valid = t_branch; + } + else /* UNDEFINED : cc=1110(AL) uses different format */ + valid = t_undefined; + break; + case 28: /* B */ + /* Format 18 */ + #if 0 + state->Reg[15] = (pc + 4 + (((tinstr & 0x3FF) << 1) + | ((tinstr & (1 << 10)) ? + 0xFFFFF800 : 0))); + #endif + //FLUSHPIPE; + valid = t_branch; + break; + case 29: + if(tinstr & 0x1) + valid = t_undefined; + else{ + /* BLX 1 for armv5t and above */ + //printf("In %s, After BLX(1),LR=0x%x,PC=0x%x, offset=0x%x\n", __FUNCTION__, state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1); + valid = t_branch; + } + break; + case 30: /* BL instruction 1 */ + /* Format 19 */ + /* There is no single ARM instruction equivalent for this Thumb + instruction. To keep the simulation simple (from the user + perspective) we check if the following instruction is the + second half of this BL, and if it is we simulate it + immediately. */ + valid = t_branch; + break; + case 31: /* BL instruction 2 */ + /* Format 19 */ + /* There is no single ARM instruction equivalent for this + instruction. Also, it should only ever be matched with the + fmt19 "BL instruction 1" instruction. However, we do allow + the simulation of it on its own, with undefined results if + r14 is not suitably initialised. */ + { + #if 0 + ARMword tmp = (pc + 2); + state->Reg[15] = + (state->Reg[14] + ((tinstr & 0x07FF) << 1)); + state->Reg[14] = (tmp | 1); + #endif + valid = t_branch; + } + break; + } + *inst_size = 2; + return valid; +} diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h new file mode 100644 index 000000000..5541de9d1 --- /dev/null +++ b/src/core/arm/dyncom/arm_dyncom_thumb.h @@ -0,0 +1,51 @@ +/* Copyright (C) +* 2011 - Michael.Kang blackfin.kang@gmail.com +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* +*/ + +/** +* @file arm_dyncom_thumb.h +* @brief The thumb dyncom +* @author Michael.Kang blackfin.kang@gmail.com +* @version 78.77 +* @date 2011-11-07 +*/ + +#ifndef __ARM_DYNCOM_THUMB_H__ +#define __ARM_DYNCOM_THUMB_H__ + +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/skyeye_types.h" + +enum tdstate { + t_undefined, // Undefined Thumb instruction + t_decoded, // Instruction decoded to ARM equivalent + t_branch, // Thumb branch (already processed) + t_uninitialized, +}; + +tdstate +thumb_translate(addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size); +static inline uint32 get_thumb_instr(uint32 instr, addr_t pc){ + uint32 tinstr; + if ((pc & 0x3) != 0) + tinstr = instr >> 16; + else + tinstr = instr & 0xFFFF; + return tinstr; +} + +#endif diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp index 0842d2f8e..ed4415082 100644 --- a/src/core/arm/interpreter/arm_interpreter.cpp +++ b/src/core/arm/interpreter/arm_interpreter.cpp @@ -4,7 +4,7 @@ #include "core/arm/interpreter/arm_interpreter.h" -const static cpu_config_t s_arm11_cpu_info = { +const static cpu_config_t arm11_cpu_info = { "armv6", "arm11", 0x0007b000, 0x0007f000, NONCACHE }; @@ -17,12 +17,11 @@ ARM_Interpreter::ARM_Interpreter() { ARMul_NewState(state); state->abort_model = 0; - state->cpu = (cpu_config_t*)&s_arm11_cpu_info; + state->cpu = (cpu_config_t*)&arm11_cpu_info; state->bigendSig = LOW; ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop); state->lateabtSig = LOW; - mmu_init(state); // Reset the core to initial state ARMul_CoProInit(state); diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h index 1e82883a2..ceb1be438 100644 --- a/src/core/arm/interpreter/arm_interpreter.h +++ b/src/core/arm/interpreter/arm_interpreter.h @@ -7,10 +7,10 @@ #include "common/common.h" #include "core/arm/arm_interface.h" -#include "core/arm/interpreter/armdefs.h" -#include "core/arm/interpreter/armemu.h" +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/armemu.h" -class ARM_Interpreter : virtual public ARM_Interface { +class ARM_Interpreter final : virtual public ARM_Interface { public: ARM_Interpreter(); @@ -20,60 +20,60 @@ public: * Set the Program Counter to an address * @param addr Address to set PC to */ - void SetPC(u32 pc); + void SetPC(u32 pc) override; /* * Get the current Program Counter * @return Returns current PC */ - u32 GetPC() const; + u32 GetPC() const override; /** * Get an ARM register * @param index Register index (0-15) * @return Returns the value in the register */ - u32 GetReg(int index) const; + u32 GetReg(int index) const override; /** * Set an ARM register * @param index Register index (0-15) * @param value Value to set register to */ - void SetReg(int index, u32 value); + void SetReg(int index, u32 value) override; /** * Get the current CPSR register * @return Returns the value of the CPSR register */ - u32 GetCPSR() const; + u32 GetCPSR() const override; /** * Set the current CPSR register * @param cpsr Value to set CPSR to */ - void SetCPSR(u32 cpsr); + void SetCPSR(u32 cpsr) override; /** * Returns the number of clock ticks since the last reset * @return Returns number of clock ticks */ - u64 GetTicks() const; + u64 GetTicks() const override; /** * Saves the current CPU context * @param ctx Thread context to save */ - void SaveContext(ThreadContext& ctx); + void SaveContext(ThreadContext& ctx) override; /** * Loads a CPU context * @param ctx Thread context to load */ - void LoadContext(const ThreadContext& ctx); + void LoadContext(const ThreadContext& ctx) override; /// Prepare core for thread reschedule (if needed to correctly handle state) - void PrepareReschedule(); + void PrepareReschedule() override; protected: @@ -81,7 +81,7 @@ protected: * Executes the given number of instructions * @param num_instructions Number of instructions to executes */ - void ExecuteInstructions(int num_instructions); + void ExecuteInstructions(int num_instructions) override; private: diff --git a/src/core/arm/interpreter/armcopro.cpp b/src/core/arm/interpreter/armcopro.cpp index 6a75e6601..b4ddc3d96 100644 --- a/src/core/arm/interpreter/armcopro.cpp +++ b/src/core/arm/interpreter/armcopro.cpp @@ -15,828 +15,311 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include "core/arm/interpreter/armdefs.h" -#include "core/arm/interpreter/armos.h" -#include "core/arm/interpreter/armemu.h" -#include "core/arm/interpreter/vfp/vfp.h" +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/armemu.h" +#include "core/arm/skyeye_common/vfp/vfp.h" //chy 2005-07-08 //#include "ansidecl.h" //chy ------- //#include "iwmmxt.h" - -//chy 2005-09-19 add CP6 MRC support (for get irq number and base) -extern unsigned xscale_cp6_mrc (ARMul_State * state, unsigned type, - ARMword instr, ARMword * data); -//chy 2005-09-19--------------- - -extern unsigned xscale_cp13_init (ARMul_State * state); -extern unsigned xscale_cp13_exit (ARMul_State * state); -extern unsigned xscale_cp13_ldc (ARMul_State * state, unsigned type, - ARMword instr, ARMword data); -extern unsigned xscale_cp13_stc (ARMul_State * state, unsigned type, - ARMword instr, ARMword * data); -extern unsigned xscale_cp13_mrc (ARMul_State * state, unsigned type, - ARMword instr, ARMword * data); -extern unsigned xscale_cp13_mcr (ARMul_State * state, unsigned type, - ARMword instr, ARMword data); -extern unsigned xscale_cp13_cdp (ARMul_State * state, unsigned type, - ARMword instr); -extern unsigned xscale_cp13_read_reg (ARMul_State * state, unsigned reg, - ARMword * data); -extern unsigned xscale_cp13_write_reg (ARMul_State * state, unsigned reg, - ARMword data); -extern unsigned xscale_cp14_init (ARMul_State * state); -extern unsigned xscale_cp14_exit (ARMul_State * state); -extern unsigned xscale_cp14_ldc (ARMul_State * state, unsigned type, - ARMword instr, ARMword data); -extern unsigned xscale_cp14_stc (ARMul_State * state, unsigned type, - ARMword instr, ARMword * data); -extern unsigned xscale_cp14_mrc (ARMul_State * state, unsigned type, - ARMword instr, ARMword * data); -extern unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, - ARMword instr, ARMword data); -extern unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, - ARMword instr); -extern unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg, - ARMword * data); -extern unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg, - ARMword data); -extern unsigned xscale_cp15_init (ARMul_State * state); -extern unsigned xscale_cp15_exit (ARMul_State * state); -extern unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, - ARMword instr, ARMword data); -extern unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, - ARMword instr, ARMword * data); -extern unsigned xscale_cp15_mrc (ARMul_State * state, unsigned type, - ARMword instr, ARMword * data); -extern unsigned xscale_cp15_mcr (ARMul_State * state, unsigned type, - ARMword instr, ARMword data); -extern unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, - ARMword instr); -extern unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg, - ARMword * data); -extern unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg, - ARMword data); -extern unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, - unsigned cpnum); - /* Dummy Co-processors. */ static unsigned -NoCoPro3R (ARMul_State * state, - unsigned a, ARMword b) +NoCoPro3R(ARMul_State * state, +unsigned a, ARMword b) { - return ARMul_CANT; + return ARMul_CANT; } static unsigned -NoCoPro4R (ARMul_State * state, - unsigned a, - ARMword b, ARMword c) +NoCoPro4R(ARMul_State * state, +unsigned a, +ARMword b, ARMword c) { - return ARMul_CANT; + return ARMul_CANT; } static unsigned -NoCoPro4W (ARMul_State * state, - unsigned a, - ARMword b, ARMword * c) +NoCoPro4W(ARMul_State * state, +unsigned a, +ARMword b, ARMword * c) { - return ARMul_CANT; + return ARMul_CANT; } static unsigned -NoCoPro5R (ARMul_State * state, - unsigned a, - ARMword b, - ARMword c, ARMword d) +NoCoPro5R(ARMul_State * state, +unsigned a, +ARMword b, +ARMword c, ARMword d) { - return ARMul_CANT; + return ARMul_CANT; } static unsigned -NoCoPro5W (ARMul_State * state, - unsigned a, - ARMword b, - ARMword * c, ARMword * d ) +NoCoPro5W(ARMul_State * state, +unsigned a, +ARMword b, +ARMword * c, ARMword * d) { - return ARMul_CANT; + return ARMul_CANT; } /* The XScale Co-processors. */ /* Coprocessor 15: System Control. */ -static void write_cp14_reg (unsigned, ARMword); -static ARMword read_cp14_reg (unsigned); - -/* There are two sets of registers for copro 15. - One set is available when opcode_2 is 0 and - the other set when opcode_2 >= 1. */ -static ARMword XScale_cp15_opcode_2_is_0_Regs[16]; -static ARMword XScale_cp15_opcode_2_is_not_0_Regs[16]; -/* There are also a set of breakpoint registers - which are accessed via CRm instead of opcode_2. */ -static ARMword XScale_cp15_DBR1; -static ARMword XScale_cp15_DBCON; -static ARMword XScale_cp15_IBCR0; -static ARMword XScale_cp15_IBCR1; - -static unsigned -XScale_cp15_init (ARMul_State * state) -{ - int i; - - for (i = 16; i--;) { - XScale_cp15_opcode_2_is_0_Regs[i] = 0; - XScale_cp15_opcode_2_is_not_0_Regs[i] = 0; - } - - /* Initialise the processor ID. */ - //chy 2003-03-24, is same as cpu id in skyeye_options.c - //XScale_cp15_opcode_2_is_0_Regs[0] = 0x69052000; - XScale_cp15_opcode_2_is_0_Regs[0] = 0x69050000; - - /* Initialise the cache type. */ - XScale_cp15_opcode_2_is_not_0_Regs[0] = 0x0B1AA1AA; - - /* Initialise the ARM Control Register. */ - XScale_cp15_opcode_2_is_0_Regs[1] = 0x00000078; - - return No_exp; -} - -/* Check an access to a register. */ - -static unsigned -check_cp15_access (ARMul_State * state, - unsigned reg, - unsigned CRm, unsigned opcode_1, unsigned opcode_2) -{ - /* Do not allow access to these register in USER mode. */ - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode == USER26MODE || state->Mode == USER32MODE ) - return ARMul_CANT; - - /* Opcode_1should be zero. */ - if (opcode_1 != 0) - return ARMul_CANT; - - /* Different register have different access requirements. */ - switch (reg) { - case 0: - case 1: - /* CRm must be 0. Opcode_2 can be anything. */ - if (CRm != 0) - return ARMul_CANT; - break; - case 2: - case 3: - /* CRm must be 0. Opcode_2 must be zero. */ - if ((CRm != 0) || (opcode_2 != 0)) - return ARMul_CANT; - break; - case 4: - /* Access not allowed. */ - return ARMul_CANT; - case 5: - case 6: - /* Opcode_2 must be zero. CRm must be 0. */ - if ((CRm != 0) || (opcode_2 != 0)) - return ARMul_CANT; - break; - case 7: - /* Permissable combinations: - Opcode_2 CRm - 0 5 - 0 6 - 0 7 - 1 5 - 1 6 - 1 10 - 4 10 - 5 2 - 6 5 */ - switch (opcode_2) { - default: - return ARMul_CANT; - case 6: - if (CRm != 5) - return ARMul_CANT; - break; - case 5: - if (CRm != 2) - return ARMul_CANT; - break; - case 4: - if (CRm != 10) - return ARMul_CANT; - break; - case 1: - if ((CRm != 5) && (CRm != 6) && (CRm != 10)) - return ARMul_CANT; - break; - case 0: - if ((CRm < 5) || (CRm > 7)) - return ARMul_CANT; - break; - } - break; - - case 8: - /* Permissable combinations: - Opcode_2 CRm - 0 5 - 0 6 - 0 7 - 1 5 - 1 6 */ - if (opcode_2 > 1) - return ARMul_CANT; - if ((CRm < 5) || (CRm > 7)) - return ARMul_CANT; - if (opcode_2 == 1 && CRm == 7) - return ARMul_CANT; - break; - case 9: - /* Opcode_2 must be zero or one. CRm must be 1 or 2. */ - if (((CRm != 0) && (CRm != 1)) - || ((opcode_2 != 1) && (opcode_2 != 2))) - return ARMul_CANT; - break; - case 10: - /* Opcode_2 must be zero or one. CRm must be 4 or 8. */ - if (((CRm != 0) && (CRm != 1)) - || ((opcode_2 != 4) && (opcode_2 != 8))) - return ARMul_CANT; - break; - case 11: - /* Access not allowed. */ - return ARMul_CANT; - case 12: - /* Access not allowed. */ - return ARMul_CANT; - case 13: - /* Opcode_2 must be zero. CRm must be 0. */ - if ((CRm != 0) || (opcode_2 != 0)) - return ARMul_CANT; - break; - case 14: - /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */ - if (opcode_2 != 0) - return ARMul_CANT; - - if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8) - && (CRm != 9)) - return ARMul_CANT; - break; - case 15: - /* Opcode_2 must be zero. CRm must be 1. */ - if ((CRm != 1) || (opcode_2 != 0)) - return ARMul_CANT; - break; - default: - /* Should never happen. */ - return ARMul_CANT; - } - - return ARMul_DONE; -} - -/* Coprocessor 13: Interrupt Controller and Bus Controller. */ - -/* There are two sets of registers for copro 13. - One set (of three registers) is available when CRm is 0 - and the other set (of six registers) when CRm is 1. */ - -static ARMword XScale_cp13_CR0_Regs[16]; -static ARMword XScale_cp13_CR1_Regs[16]; - -static unsigned -XScale_cp13_init (ARMul_State * state) -{ - int i; - - for (i = 16; i--;) { - XScale_cp13_CR0_Regs[i] = 0; - XScale_cp13_CR1_Regs[i] = 0; - } - - return No_exp; -} - -/* Check an access to a register. */ - -static unsigned -check_cp13_access (ARMul_State * state, - unsigned reg, - unsigned CRm, unsigned opcode_1, unsigned opcode_2) -{ - /* Do not allow access to these registers in USER mode. */ - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode == USER26MODE || state->Mode == USER32MODE ) - return ARMul_CANT; - - /* The opcodes should be zero. */ - if ((opcode_1 != 0) || (opcode_2 != 0)) - return ARMul_CANT; - - /* Do not allow access to these register if bit - 13 of coprocessor 15's register 15 is zero. */ - if (!CP_ACCESS_ALLOWED (state, 13)) - return ARMul_CANT; - - /* Registers 0, 4 and 8 are defined when CRm == 0. - Registers 0, 1, 4, 5, 6, 7, 8 are defined when CRm == 1. - For all other CRm values undefined behaviour results. */ - if (CRm == 0) { - if (reg == 0 || reg == 4 || reg == 8) - return ARMul_DONE; - } - else if (CRm == 1) { - if (reg == 0 || reg == 1 || (reg >= 4 && reg <= 8)) - return ARMul_DONE; - } - - return ARMul_CANT; -} - -/* Coprocessor 14: Performance Monitoring, Clock and Power management, - Software Debug. */ - -static ARMword XScale_cp14_Regs[16]; - -static unsigned -XScale_cp14_init (ARMul_State * state) -{ - int i; - - for (i = 16; i--;) - XScale_cp14_Regs[i] = 0; - - return No_exp; -} +static void write_cp14_reg(unsigned, ARMword); +static ARMword read_cp14_reg(unsigned); /* Check an access to a register. */ static unsigned -check_cp14_access (ARMul_State * state, - unsigned reg, - unsigned CRm, unsigned opcode1, unsigned opcode2) -{ - /* Not allowed to access these register in USER mode. */ - //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode - if (state->Mode == USER26MODE || state->Mode == USER32MODE ) - return ARMul_CANT; - - /* CRm should be zero. */ - if (CRm != 0) - return ARMul_CANT; - - /* OPcodes should be zero. */ - if (opcode1 != 0 || opcode2 != 0) - return ARMul_CANT; - - /* Accessing registers 4 or 5 has unpredicatable results. */ - if (reg >= 4 && reg <= 5) - return ARMul_CANT; - - return ARMul_DONE; -} - -/* Here's ARMulator's MMU definition. A few things to note: - 1) It has eight registers, but only two are defined. - 2) You can only access its registers with MCR and MRC. - 3) MMU Register 0 (ID) returns 0x41440110 - 4) Register 1 only has 4 bits defined. Bits 0 to 3 are unused, bit 4 - controls 32/26 bit program space, bit 5 controls 32/26 bit data space, - bit 6 controls late abort timimg and bit 7 controls big/little endian. */ - -static ARMword MMUReg[8]; - -static unsigned -MMUInit (ARMul_State * state) -{ -/* 2004-05-09 chy -------------------------------------------------------------- -read ARM Architecture Reference Manual -2.6.5 Data Abort -There are three Abort Model in ARM arch. - -Early Abort Model: used in some ARMv3 and earlier implementations. In this -model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and -the base register was unchanged for all other instructions. (oldest) - -Base Restored Abort Model: If a Data Abort occurs in an instruction which -specifies base register writeback, the value in the base register is -unchanged. (strongarm, xscale) - -Base Updated Abort Model: If a Data Abort occurs in an instruction which -specifies base register writeback, the base register writeback still occurs. -(arm720T) - -read PART B -chap2 The System Control Coprocessor CP15 -2.4 Register1:control register -L(bit 6): in some ARMv3 and earlier implementations, the abort model of the -processor could be configured: -0=early Abort Model Selected(now obsolete) -1=Late Abort Model selceted(same as Base Updated Abort Model) - -on later processors, this bit reads as 1 and ignores writes. -------------------------------------------------------------- -So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) - if lateabtSig=0, then it means Base Restored Abort Model -because the ARMs which skyeye simulates are all belonged to ARMv4, -so I think MMUReg[1]'s bit 6 should always be 1 - -*/ - - MMUReg[1] = state->prog32Sig << 4 | - state->data32Sig << 5 | 1 << 6 | state->bigendSig << 7; - //state->data32Sig << 5 | state->lateabtSig << 6 | state->bigendSig << 7; - - - NOTICE_LOG(ARM11, "ARMul_ConsolePrint: MMU present"); - - return TRUE; -} - -static unsigned -MMUMRC (ARMul_State * state, unsigned type, - ARMword instr, ARMword * value) -{ - mmu_mrc (state, instr, value); - return (ARMul_DONE); -} - -static unsigned -MMUMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value) -{ - mmu_mcr (state, instr, value); - return (ARMul_DONE); -} - -/* What follows is the Validation Suite Coprocessor. It uses two - co-processor numbers (4 and 5) and has the follwing functionality. - Sixteen registers. Both co-processor nuimbers can be used in an MCR - and MRC to access these registers. CP 4 can LDC and STC to and from - the registers. CP 4 and CP 5 CDP 0 will busy wait for the number of - cycles specified by a CP register. CP 5 CDP 1 issues a FIQ after a - number of cycles (specified in a CP register), CDP 2 issues an IRQW - in the same way, CDP 3 and 4 turn of the FIQ and IRQ source, and CDP 5 - stores a 32 bit time value in a CP register (actually it's the total - number of N, S, I, C and F cyles). */ - -static ARMword ValReg[16]; - -static unsigned -ValLDC (ARMul_State * state, - unsigned type, ARMword instr, ARMword data) -{ - static unsigned words; - - if (type != ARMul_DATA) - words = 0; - else { - ValReg[BITS (12, 15)] = data; - - if (BIT (22)) - /* It's a long access, get two words. */ - if (words++ != 4) - return ARMul_INC; - } - - return ARMul_DONE; -} - -static unsigned -ValSTC (ARMul_State * state, - unsigned type, ARMword instr, ARMword * data) -{ - static unsigned words; - - if (type != ARMul_DATA) - words = 0; - else { - *data = ValReg[BITS (12, 15)]; - - if (BIT (22)) - /* It's a long access, get two words. */ - if (words++ != 4) - return ARMul_INC; - } - - return ARMul_DONE; -} - -static unsigned -ValMRC (ARMul_State * state, - unsigned type, ARMword instr, ARMword * value) -{ - *value = ValReg[BITS (16, 19)]; - - return ARMul_DONE; -} - -static unsigned -ValMCR (ARMul_State * state, - unsigned type, ARMword instr, ARMword value) -{ - ValReg[BITS (16, 19)] = value; - - return ARMul_DONE; -} - -static unsigned -ValCDP (ARMul_State * state, unsigned type, ARMword instr) -{ - static unsigned int finish = 0; - - if (BITS (20, 23) != 0) - return ARMul_CANT; - - if (type == ARMul_FIRST) { - ARMword howlong; - - howlong = ValReg[BITS (0, 3)]; - - /* First cycle of a busy wait. */ - finish = ARMul_Time (state) + howlong; - - return howlong == 0 ? ARMul_DONE : ARMul_BUSY; - } - else if (type == ARMul_BUSY) { - if (ARMul_Time (state) >= finish) - return ARMul_DONE; - else - return ARMul_BUSY; - } - - return ARMul_CANT; -} - -static unsigned -DoAFIQ (ARMul_State * state) -{ - state->NfiqSig = LOW; - return 0; -} - -static unsigned -DoAIRQ (ARMul_State * state) -{ - state->NirqSig = LOW; - return 0; -} - -static unsigned -IntCDP (ARMul_State * state, unsigned type, ARMword instr) +check_cp15_access(ARMul_State * state, +unsigned reg, +unsigned CRm, unsigned opcode_1, unsigned opcode_2) { - static unsigned int finish; - ARMword howlong; - - howlong = ValReg[BITS (0, 3)]; - - switch ((int) BITS (20, 23)) { - case 0: - if (type == ARMul_FIRST) { - /* First cycle of a busy wait. */ - finish = ARMul_Time (state) + howlong; - - return howlong == 0 ? ARMul_DONE : ARMul_BUSY; - } - else if (type == ARMul_BUSY) { - if (ARMul_Time (state) >= finish) - return ARMul_DONE; - else - return ARMul_BUSY; - } - return ARMul_DONE; - - case 1: - if (howlong == 0) - ARMul_Abort (state, ARMul_FIQV); - else - ARMul_ScheduleEvent (state, howlong, DoAFIQ); - return ARMul_DONE; - - case 2: - if (howlong == 0) - ARMul_Abort (state, ARMul_IRQV); - else - ARMul_ScheduleEvent (state, howlong, DoAIRQ); - return ARMul_DONE; - - case 3: - state->NfiqSig = HIGH; - return ARMul_DONE; - - case 4: - state->NirqSig = HIGH; - return ARMul_DONE; - - case 5: - ValReg[BITS (0, 3)] = ARMul_Time (state); - return ARMul_DONE; - } - - return ARMul_CANT; + /* Do not allow access to these register in USER mode. */ + //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode + if (state->Mode == USER26MODE || state->Mode == USER32MODE) + return ARMul_CANT; + + /* Opcode_1should be zero. */ + if (opcode_1 != 0) + return ARMul_CANT; + + /* Different register have different access requirements. */ + switch (reg) { + case 0: + case 1: + /* CRm must be 0. Opcode_2 can be anything. */ + if (CRm != 0) + return ARMul_CANT; + break; + case 2: + case 3: + /* CRm must be 0. Opcode_2 must be zero. */ + if ((CRm != 0) || (opcode_2 != 0)) + return ARMul_CANT; + break; + case 4: + /* Access not allowed. */ + return ARMul_CANT; + case 5: + case 6: + /* Opcode_2 must be zero. CRm must be 0. */ + if ((CRm != 0) || (opcode_2 != 0)) + return ARMul_CANT; + break; + case 7: + /* Permissable combinations: + Opcode_2 CRm + 0 5 + 0 6 + 0 7 + 1 5 + 1 6 + 1 10 + 4 10 + 5 2 + 6 5 */ + switch (opcode_2) { + default: + return ARMul_CANT; + case 6: + if (CRm != 5) + return ARMul_CANT; + break; + case 5: + if (CRm != 2) + return ARMul_CANT; + break; + case 4: + if (CRm != 10) + return ARMul_CANT; + break; + case 1: + if ((CRm != 5) && (CRm != 6) && (CRm != 10)) + return ARMul_CANT; + break; + case 0: + if ((CRm < 5) || (CRm > 7)) + return ARMul_CANT; + break; + } + break; + + case 8: + /* Permissable combinations: + Opcode_2 CRm + 0 5 + 0 6 + 0 7 + 1 5 + 1 6 */ + if (opcode_2 > 1) + return ARMul_CANT; + if ((CRm < 5) || (CRm > 7)) + return ARMul_CANT; + if (opcode_2 == 1 && CRm == 7) + return ARMul_CANT; + break; + case 9: + /* Opcode_2 must be zero or one. CRm must be 1 or 2. */ + if (((CRm != 0) && (CRm != 1)) + || ((opcode_2 != 1) && (opcode_2 != 2))) + return ARMul_CANT; + break; + case 10: + /* Opcode_2 must be zero or one. CRm must be 4 or 8. */ + if (((CRm != 0) && (CRm != 1)) + || ((opcode_2 != 4) && (opcode_2 != 8))) + return ARMul_CANT; + break; + case 11: + /* Access not allowed. */ + return ARMul_CANT; + case 12: + /* Access not allowed. */ + return ARMul_CANT; + case 13: + /* Opcode_2 must be zero. CRm must be 0. */ + if ((CRm != 0) || (opcode_2 != 0)) + return ARMul_CANT; + break; + case 14: + /* Opcode_2 must be 0. CRm must be 0, 3, 4, 8 or 9. */ + if (opcode_2 != 0) + return ARMul_CANT; + + if ((CRm != 0) && (CRm != 3) && (CRm != 4) && (CRm != 8) + && (CRm != 9)) + return ARMul_CANT; + break; + case 15: + /* Opcode_2 must be zero. CRm must be 1. */ + if ((CRm != 1) || (opcode_2 != 0)) + return ARMul_CANT; + break; + default: + /* Should never happen. */ + return ARMul_CANT; + } + + return ARMul_DONE; } /* Install co-processor instruction handlers in this routine. */ unsigned -ARMul_CoProInit (ARMul_State * state) +ARMul_CoProInit(ARMul_State * state) { - unsigned int i; - - /* Initialise tham all first. */ - for (i = 0; i < 16; i++) - ARMul_CoProDetach (state, i); - - /* Install CoPro Instruction handlers here. - The format is: - ARMul_CoProAttach (state, CP Number, Init routine, Exit routine - LDC routine, STC routine, MRC routine, MCR routine, - CDP routine, Read Reg routine, Write Reg routine). */ - if (state->is_ep9312) { - ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4, - DSPMRC4, DSPMCR4, NULL, NULL, DSPCDP4, NULL, NULL); - ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5, - DSPMRC5, DSPMCR5, NULL, NULL, DSPCDP5, NULL, NULL); - ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL, - DSPMRC6, DSPMCR6, NULL, NULL, DSPCDP6, NULL, NULL); - } - else { - ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC, - ValMRC, ValMCR, NULL, NULL, ValCDP, NULL, NULL); - - ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL, - ValMRC, ValMCR, NULL, NULL, IntCDP, NULL, NULL); - } - - if (state->is_XScale) { - //chy 2005-09-19, for PXA27x's CP6 - if (state->is_pxa27x) { - ARMul_CoProAttach (state, 6, NULL, NULL, - NULL, NULL, xscale_cp6_mrc, - NULL, NULL, NULL, NULL, NULL, NULL); - } - //chy 2005-09-19 end------------- - ARMul_CoProAttach (state, 13, xscale_cp13_init, - xscale_cp13_exit, xscale_cp13_ldc, - xscale_cp13_stc, xscale_cp13_mrc, - xscale_cp13_mcr, NULL, NULL, xscale_cp13_cdp, - xscale_cp13_read_reg, - xscale_cp13_write_reg); - - ARMul_CoProAttach (state, 14, xscale_cp14_init, - xscale_cp14_exit, xscale_cp14_ldc, - xscale_cp14_stc, xscale_cp14_mrc, - xscale_cp14_mcr, NULL, NULL, xscale_cp14_cdp, - xscale_cp14_read_reg, - xscale_cp14_write_reg); - //chy: 2003-08-24. - ARMul_CoProAttach (state, 15, xscale_cp15_init, - xscale_cp15_exit, xscale_cp15_ldc, - xscale_cp15_stc, xscale_cp15_mrc, - xscale_cp15_mcr, NULL, NULL, xscale_cp15_cdp, - xscale_cp15_read_reg, - xscale_cp15_write_reg); - } - else if (state->is_v6) { - ARMul_CoProAttach (state, 10, VFPInit, NULL, VFPLDC, VFPSTC, - VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); - ARMul_CoProAttach (state, 11, VFPInit, NULL, VFPLDC, VFPSTC, - VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); - - ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, - MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL); - } - else { //all except xscale - ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, - // MMUMRC, MMUMCR, NULL, MMURead, MMUWrite); - MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL); - } -//chy 2003-09-03 do it in future!!!!???? + unsigned int i; + + /* Initialise tham all first. */ + for (i = 0; i < 16; i++) + ARMul_CoProDetach(state, i); + + /* Install CoPro Instruction handlers here. + The format is: + ARMul_CoProAttach (state, CP Number, Init routine, Exit routine + LDC routine, STC routine, MRC routine, MCR routine, + CDP routine, Read Reg routine, Write Reg routine). */ + if (state->is_v6) { + ARMul_CoProAttach(state, 10, VFPInit, NULL, VFPLDC, VFPSTC, + VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); + ARMul_CoProAttach(state, 11, VFPInit, NULL, VFPLDC, VFPSTC, + VFPMRC, VFPMCR, VFPMRRC, VFPMCRR, VFPCDP, NULL, NULL); + + /*ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, + MMUMRC, MMUMCR, NULL, NULL, NULL, NULL, NULL);*/ + } + //chy 2003-09-03 do it in future!!!!???? #if 0 - if (state->is_iWMMXt) { - ARMul_CoProAttach (state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC, - NULL, NULL, IwmmxtCDP, NULL, NULL); - - ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL, - IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, - NULL); - } + if (state->is_iWMMXt) { + ARMul_CoProAttach(state, 0, NULL, NULL, IwmmxtLDC, IwmmxtSTC, + NULL, NULL, IwmmxtCDP, NULL, NULL); + + ARMul_CoProAttach(state, 1, NULL, NULL, NULL, NULL, + IwmmxtMRC, IwmmxtMCR, IwmmxtCDP, NULL, + NULL); + } #endif - //----------------------------------------------------------------------------- - //chy 2004-05-25, found the user/system code visit CP 1,2, so I add below code. - ARMul_CoProAttach (state, 1, NULL, NULL, NULL, NULL, - ValMRC, ValMCR, NULL, NULL, NULL, NULL, NULL); - ARMul_CoProAttach (state, 2, NULL, NULL, ValLDC, ValSTC, - NULL, NULL, NULL, NULL, NULL, NULL, NULL); - //------------------------------------------------------------------------------ - /* No handlers below here. */ - - /* Call all the initialisation routines. */ - for (i = 0; i < 16; i++) - if (state->CPInit[i]) - (state->CPInit[i]) (state); - - return TRUE; + /* No handlers below here. */ + + /* Call all the initialisation routines. */ + for (i = 0; i < 16; i++) + if (state->CPInit[i]) + (state->CPInit[i]) (state); + + return TRUE; } /* Install co-processor finalisation routines in this routine. */ void -ARMul_CoProExit (ARMul_State * state) +ARMul_CoProExit(ARMul_State * state) { - register unsigned i; + register unsigned i; - for (i = 0; i < 16; i++) - if (state->CPExit[i]) - (state->CPExit[i]) (state); + for (i = 0; i < 16; i++) + if (state->CPExit[i]) + (state->CPExit[i]) (state); - for (i = 0; i < 16; i++) /* Detach all handlers. */ - ARMul_CoProDetach (state, i); + for (i = 0; i < 16; i++) /* Detach all handlers. */ + ARMul_CoProDetach(state, i); } /* Routines to hook Co-processors into ARMulator. */ void -ARMul_CoProAttach (ARMul_State * state, - unsigned number, - ARMul_CPInits * init, - ARMul_CPExits * exit, - ARMul_LDCs * ldc, - ARMul_STCs * stc, - ARMul_MRCs * mrc, - ARMul_MCRs * mcr, - ARMul_MRRCs * mrrc, - ARMul_MCRRs * mcrr, - ARMul_CDPs * cdp, - ARMul_CPReads * read, ARMul_CPWrites * write) -{ - if (init != NULL) - state->CPInit[number] = init; - if (exit != NULL) - state->CPExit[number] = exit; - if (ldc != NULL) - state->LDC[number] = ldc; - if (stc != NULL) - state->STC[number] = stc; - if (mrc != NULL) - state->MRC[number] = mrc; - if (mcr != NULL) - state->MCR[number] = mcr; - if (mrrc != NULL) - state->MRRC[number] = mrrc; - if (mcrr != NULL) - state->MCRR[number] = mcrr; - if (cdp != NULL) - state->CDP[number] = cdp; - if (read != NULL) - state->CPRead[number] = read; - if (write != NULL) - state->CPWrite[number] = write; -} - -void -ARMul_CoProDetach (ARMul_State * state, unsigned number) +ARMul_CoProAttach(ARMul_State * state, +unsigned number, +ARMul_CPInits * init, +ARMul_CPExits * exit, +ARMul_LDCs * ldc, +ARMul_STCs * stc, +ARMul_MRCs * mrc, +ARMul_MCRs * mcr, +ARMul_MRRCs * mrrc, +ARMul_MCRRs * mcrr, +ARMul_CDPs * cdp, +ARMul_CPReads * read, ARMul_CPWrites * write) { - ARMul_CoProAttach (state, number, NULL, NULL, - NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R, - NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL); - - state->CPInit[number] = NULL; - state->CPExit[number] = NULL; - state->CPRead[number] = NULL; - state->CPWrite[number] = NULL; + if (init != NULL) + state->CPInit[number] = init; + if (exit != NULL) + state->CPExit[number] = exit; + if (ldc != NULL) + state->LDC[number] = ldc; + if (stc != NULL) + state->STC[number] = stc; + if (mrc != NULL) + state->MRC[number] = mrc; + if (mcr != NULL) + state->MCR[number] = mcr; + if (mrrc != NULL) + state->MRRC[number] = mrrc; + if (mcrr != NULL) + state->MCRR[number] = mcrr; + if (cdp != NULL) + state->CDP[number] = cdp; + if (read != NULL) + state->CPRead[number] = read; + if (write != NULL) + state->CPWrite[number] = write; } -//chy 2003-09-03:below funs just replace the old ones - -/* Set the XScale FSR and FAR registers. */ - void -XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far) -{ - //if (!state->is_XScale || (read_cp14_reg (10) & (1UL << 31)) == 0) - if (!state->is_XScale) - return; - //assume opcode2=0 crm =0 - xscale_cp15_write_reg (state, 5, fsr); - xscale_cp15_write_reg (state, 6, _far); -} - -//chy 2003-09-03 seems 0 is CANT, 1 is DONE ???? -int -XScale_debug_moe (ARMul_State * state, int moe) +ARMul_CoProDetach(ARMul_State * state, unsigned number) { - //chy 2003-09-03 , W/R CP14 reg, now it's no use ???? - printf ("SKYEYE: XScale_debug_moe called !!!!\n"); - return 1; + ARMul_CoProAttach(state, number, NULL, NULL, + NoCoPro4R, NoCoPro4W, NoCoPro4W, NoCoPro4R, + NoCoPro5W, NoCoPro5R, NoCoPro3R, NULL, NULL); + + state->CPInit[number] = NULL; + state->CPExit[number] = NULL; + state->CPRead[number] = NULL; + state->CPWrite[number] = NULL; } diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index f9130ef88..73223874e 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -18,9 +18,9 @@ //#include <util.h> // DEBUG() -#include "arm_regformat.h" -#include "armdefs.h" -#include "armemu.h" +#include "core/arm/skyeye_common/arm_regformat.h" +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/armemu.h" #include "core/hle/hle.h" //#include "svc.h" @@ -28,9 +28,6 @@ //ichfly //#define callstacker 1 - -//#include "armos.h" - //#include "skyeye_callback.h" //#include "skyeye_bus.h" //#include "sim_control.h" @@ -66,13 +63,6 @@ static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int); static void Handle_Load_Double (ARMul_State *, ARMword); static void Handle_Store_Double (ARMul_State *, ARMword); -void -XScale_set_fsr_far (ARMul_State * state, ARMword fsr, ARMword _far); -int -XScale_debug_moe (ARMul_State * state, int moe); -unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, - unsigned cpnum); - static int handle_v6_insn (ARMul_State * state, ARMword instr); @@ -379,7 +369,7 @@ ARMul_Emulate26 (ARMul_State * state) #endif { /* The PC pipeline value depends on whether ARM - or Thumb instructions are being + or Thumb instructions are being d. */ ARMword isize; ARMword instr; /* The current instruction. */ @@ -541,6 +531,7 @@ ARMul_Emulate26 (ARMul_State * state) state->AbortAddr = 1; instr = ARMul_LoadInstrN (state, pc, isize); + //chy 2006-04-12, for ICE debug have_bp=ARMul_ICE_debug(state,instr,pc); #if 0 @@ -565,6 +556,7 @@ ARMul_Emulate26 (ARMul_State * state) } printf("\n"); #endif + instr = ARMul_LoadInstrN (state, pc, isize); state->last_instr = state->CurrInstr; state->CurrInstr = instr; @@ -955,9 +947,8 @@ ARMul_Emulate26 (ARMul_State * state) case t_decoded: /* ARM instruction available. */ //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp); - - if (armOp == 0xDEADC0DE) - { + + if (armOp == 0xDEADC0DE) { DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc); } @@ -970,7 +961,6 @@ ARMul_Emulate26 (ARMul_State * state) } } #endif - /* Check the condition codes. */ if ((temp = TOPBITS (28)) == AL) { /* Vile deed in the need for speed. */ @@ -1127,6 +1117,7 @@ ARMul_Emulate26 (ARMul_State * state) //chy 2003-08-24 now #if 0 .... #endif process cp14, cp15.reg14, I disable it... + /* Actual execution of instructions begins here. */ /* If the condition codes don't match, stop here. */ if (temp) { @@ -2311,12 +2302,9 @@ mainswitch: if (state->Aborted) { TAKEABORT; } - if (enter) - { + if (enter) { state->Reg[DESTReg] = 0; - } - else - { + } else { state->Reg[DESTReg] = 1; } break; @@ -3066,7 +3054,27 @@ mainswitch: break; case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ - if (BIT (4)) { + //ichfly PKHBT PKHTB todo check this + if ((instr & 0x70) == 0x10) //pkhbt + { + u8 idest = BITS(12, 15); + u8 rfis = BITS(16, 19); + u8 rlast = BITS(0, 3); + u8 ishi = BITS(7,11); + state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); + break; + } + else if ((instr & 0x70) == 0x50)//pkhtb + { + u8 idest = BITS(12, 15); + u8 rfis = BITS(16, 19); + u8 rlast = BITS(0, 3); + u8 ishi = BITS(7, 11); + if (ishi == 0)ishi = 0x20; + state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000); + break; + } + else if (BIT (4)) { #ifdef MODE32 if (state->is_v6 && handle_v6_insn (state, instr)) @@ -3678,7 +3686,13 @@ mainswitch: /* Co-Processor Data Transfers. */ case 0xc4: - if (state->is_v5) { + if ((instr & 0x0FF00FF0) == 0xC400B10) //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0 + { + state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)]; + state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)]; + break; + } + else if (state->is_v5) { /* Reading from R15 is UNPREDICTABLE. */ if (BITS (12, 15) == 15 || BITS (16, 19) == 15) ARMul_UndefInstr (state, instr); @@ -3698,13 +3712,21 @@ mainswitch: break; case 0xc5: - if (state->is_v5) { + if ((instr & 0x00000FF0) == 0xB10) //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0 + { + state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1]; + state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1]; + break; + } + else if (state->is_v5) { /* Writes to R15 are UNPREDICATABLE. */ if (DESTReg == 15 || LHSReg == 15) ARMul_UndefInstr (state, instr); /* Is access to the coprocessor allowed ? */ else if (!CP_ACCESS_ALLOWED(state, CPNum)) - ARMul_UndefInstr (state, instr); + { + ARMul_UndefInstr(state, instr); + } else { /* MRRC, ARMv5TE and up */ ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); @@ -4062,9 +4084,11 @@ TEST_EMULATE: // continue; else if (state->Emulate != RUN) break; - } - while (state->NumInstrsToExecute--); + + } + while (state->NumInstrsToExecute); +exit: state->decoded = decoded; state->loaded = loaded; state->pc = pc; @@ -5689,12 +5713,98 @@ L_stm_s_takeabort: case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break; +#endif case 0x61: - printf ("Unhandled v6 insn: sadd/ssub\n"); + if ((instr & 0xFF0) == 0xf70)//ssub16 + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = (a1 - a2)&0xFFFF | (((b1 - b2)&0xFFFF)<< 0x10); + return 1; + } + else if ((instr & 0xFF0) == 0xf10)//sadd16 + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10); + return 1; + } + else if ((instr & 0xFF0) == 0xf50)//ssax + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10); + return 1; + } + else if ((instr & 0xFF0) == 0xf30)//sasx + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10); + return 1; + } + else printf ("Unhandled v6 insn: sadd/ssub\n"); break; case 0x62: - printf ("Unhandled v6 insn: qadd/qsub\n"); + if ((instr & 0xFF0) == 0xf70)//QSUB16 + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + s32 res1 = (a1 - b1); + s32 res2 = (a2 - b2); + if (res1 > 0x7FFF) res1 = 0x7FFF; + if (res2 > 0x7FFF) res2 = 0x7FFF; + if (res1 < 0x7FFF) res1 = -0x8000; + if (res2 < 0x7FFF) res2 = -0x8000; + state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10); + return 1; + } + else if ((instr & 0xFF0) == 0xf10)//QADD16 + { + u8 tar = BITS(12, 15); + u8 src1 = BITS(16, 19); + u8 src2 = BITS(0, 3); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = (state->Reg[src2] & 0xFFFF); + s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); + s32 res1 = (a1 + b1); + s32 res2 = (a2 + b2); + if (res1 > 0x7FFF) res1 = 0x7FFF; + if (res2 > 0x7FFF) res2 = 0x7FFF; + if (res1 < 0x7FFF) res1 = -0x8000; + if (res2 < 0x7FFF) res2 = -0x8000; + state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10); + return 1; + } + else printf ("Unhandled v6 insn: qadd/qsub\n"); break; +#if 0 case 0x63: printf ("Unhandled v6 insn: shadd/shsub\n"); break; @@ -5712,10 +5822,65 @@ L_stm_s_takeabort: break; #endif case 0x6c: - printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); + if ((instr & 0xf03f0) == 0xf0070) //uxtb16 + { + u8 src1 = BITS(0, 3); + u8 tar = BITS(12, 15); + u32 base = state->Reg[src1]; + u32 shamt = BITS(9,10)* 8; + u32 in = ((base << (32 - shamt)) | (base >> shamt)); + state->Reg[tar] = in & 0x00FF00FF; + return 1; + } + else + printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); break; case 0x70: - printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); + if ((instr & 0xf0d0) == 0xf010)//smuad //ichfly + { + u8 tar = BITS(16, 19); + u8 src1 = BITS(0, 3); + u8 src2 = BITS(8, 11); + u8 swap = BIT(5); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); + s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = a1*a2 + b1*b2; + return 1; + + } + else if ((instr & 0xf0d0) == 0xf050)//smusd + { + u8 tar = BITS(16, 19); + u8 src1 = BITS(0, 3); + u8 src2 = BITS(8, 11); + u8 swap = BIT(5); + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); + s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = a1*a2 - b1*b2; + return 1; + } + else if ((instr & 0xd0) == 0x10)//smlad + { + u8 tar = BITS(16, 19); + u8 src1 = BITS(0, 3); + u8 src2 = BITS(8, 11); + u8 src3 = BITS(12, 15); + u8 swap = BIT(5); + + u32 a3 = state->Reg[src3]; + + s16 a1 = (state->Reg[src1] & 0xFFFF); + s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); + s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); + s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); + state->Reg[tar] = a1*a2 + b1*b2 + a3; + return 1; + } + else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); break; case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); @@ -5753,13 +5918,10 @@ L_stm_s_takeabort: if (state->Aborted) { TAKEABORT; } - - if (enter) - { + + if (enter) { state->Reg[DESTReg] = 0; - } - else - { + } else { state->Reg[DESTReg] = 1; } @@ -5798,12 +5960,9 @@ L_stm_s_takeabort: } - if (enter) - { + if (enter) { state->Reg[DESTReg] = 0; - } - else - { + } else { state->Reg[DESTReg] = 1; } @@ -5856,8 +6015,25 @@ L_stm_s_takeabort: case 0x01: case 0xf3: - printf ("Unhandled v6 insn: ssat\n"); - return 0; + //ichfly + //SSAT16 + { + u8 tar = BITS(12,15); + u8 src = BITS(0, 3); + u8 val = BITS(16, 19) + 1; + s16 a1 = (state->Reg[src]); + s16 a2 = (state->Reg[src] >> 0x10); + s16 min = (s16)(0x8000) >> (16 - val); + s16 max = 0x7FFF >> (16 - val); + if (min > a1) a1 = min; + if (max < a1) a1 = max; + if (min > a2) a2 = min; + if (max < a2) a2 = max; + u32 temp2 = ((u32)(a2)) << 0x10; + state->Reg[tar] = (a1&0xFFFF) | (temp2); + } + + return 1; default: break; } @@ -5947,8 +6123,21 @@ L_stm_s_takeabort: case 0x01: case 0xf3: - printf ("Unhandled v6 insn: usat\n"); - return 0; + //ichfly + //USAT16 + { + u8 tar = BITS(12, 15); + u8 src = BITS(0, 3); + u8 val = BITS(16, 19); + s16 a1 = (state->Reg[src]); + s16 a2 = (state->Reg[src] >> 0x10); + s16 max = 0xFFFF >> (16 - val); + if (max < a1) a1 = max; + if (max < a2) a2 = max; + u32 temp2 = ((u32)(a2)) << 0x10; + state->Reg[tar] = (a1 & 0xFFFF) | (temp2); + } + return 1; default: break; } diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index 6fbab3bfb..03bca2870 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp @@ -17,8 +17,8 @@ //#include <unistd.h> -#include "core/arm/interpreter/armdefs.h" -#include "core/arm/interpreter/armemu.h" +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/armemu.h" /***************************************************************************\ * Definitions for the emulator architecture * diff --git a/src/core/arm/interpreter/armmmu.cpp b/src/core/arm/interpreter/armmmu.cpp deleted file mode 100644 index 242e6a83c..000000000 --- a/src/core/arm/interpreter/armmmu.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* - armmmu.c - Memory Management Unit emulation. - ARMulator extensions for the ARM7100 family. - Copyright (C) 1999 Ben Williamson - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <assert.h> -#include <string.h> -#include "armdefs.h" -/* two header for arm disassemble */ -//#include "skyeye_arch.h" -#include "armcpu.h" - - -extern mmu_ops_t xscale_mmu_ops; -exception_t arm_mmu_write(short size, u32 addr, uint32_t *value); -exception_t arm_mmu_read(short size, u32 addr, uint32_t *value); -#define MMU_OPS (state->mmu.ops) -ARMword skyeye_cachetype = -1; - -int -mmu_init (ARMul_State * state) -{ - int ret; - - state->mmu.control = 0x70; - state->mmu.translation_table_base = 0xDEADC0DE; - state->mmu.domain_access_control = 0xDEADC0DE; - state->mmu.fault_status = 0; - state->mmu.fault_address = 0; - state->mmu.process_id = 0; - - switch (state->cpu->cpu_val & state->cpu->cpu_mask) { - //case SA1100: - //case SA1110: - // NOTICE_LOG(ARM11, "SKYEYE: use sa11xx mmu ops\n"); - // state->mmu.ops = sa_mmu_ops; - // break; - //case PXA250: - //case PXA270: //xscale - // NOTICE_LOG(ARM11, "SKYEYE: use xscale mmu ops\n"); - // state->mmu.ops = xscale_mmu_ops; - // break; - //case 0x41807200: //arm720t - //case 0x41007700: //arm7tdmi - //case 0x41007100: //arm7100 - // NOTICE_LOG(ARM11, "SKYEYE: use arm7100 mmu ops\n"); - // state->mmu.ops = arm7100_mmu_ops; - // break; - //case 0x41009200: - // NOTICE_LOG(ARM11, "SKYEYE: use arm920t mmu ops\n"); - // state->mmu.ops = arm920t_mmu_ops; - // break; - //case 0x41069260: - // NOTICE_LOG(ARM11, "SKYEYE: use arm926ejs mmu ops\n"); - // state->mmu.ops = arm926ejs_mmu_ops; - // break; - /* case 0x560f5810: */ - case 0x0007b000: - NOTICE_LOG(ARM11, "SKYEYE: use arm11jzf-s mmu ops\n"); - state->mmu.ops = arm1176jzf_s_mmu_ops; - break; - - default: - ERROR_LOG (ARM11, - "SKYEYE: armmmu.c : mmu_init: unknown cpu_val&cpu_mask 0x%x\n", - state->cpu->cpu_val & state->cpu->cpu_mask); - break; - - }; - ret = state->mmu.ops.init (state); - state->mmu_inited = (ret == 0); - /* initialize mmu_read and mmu_write for disassemble */ - //skyeye_config_t *config = get_current_config(); - //generic_arch_t *arch_instance = get_arch_instance(config->arch->arch_name); - //arch_instance->mmu_read = arm_mmu_read; - //arch_instance->mmu_write = arm_mmu_write; - - return ret; -} - -int -mmu_reset (ARMul_State * state) -{ - if (state->mmu_inited) - mmu_exit (state); - return mmu_init (state); -} - -void -mmu_exit (ARMul_State * state) -{ - MMU_OPS.exit (state); - state->mmu_inited = 0; -} - -fault_t -mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - return MMU_OPS.read_byte (state, virt_addr, data); -}; - -fault_t -mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - return MMU_OPS.read_halfword (state, virt_addr, data); -}; - -fault_t -mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - return MMU_OPS.read_word (state, virt_addr, data); -}; - -fault_t -mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - fault_t fault; - //static int count = 0; - //count ++; - fault = MMU_OPS.write_byte (state, virt_addr, data); - return fault; -} - -fault_t -mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - fault_t fault; - //static int count = 0; - //count ++; - fault = MMU_OPS.write_halfword (state, virt_addr, data); - return fault; -} - -fault_t -mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - fault_t fault; - fault = MMU_OPS.write_word (state, virt_addr, data); - - /*used for debug for MMU* - - if (!fault){ - ARMword tmp; - - if (mmu_read_word(state, virt_addr, &tmp)){ - err_msg("load back\n"); - exit(-1); - }else{ - if (tmp != data){ - err_msg("load back not equal %d %x\n", count, virt_addr); - } - } - } - */ - - return fault; -}; - -fault_t -mmu_load_instr (ARMul_State * state, ARMword virt_addr, ARMword * instr) -{ - return MMU_OPS.load_instr (state, virt_addr, instr); -} - -ARMword -mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) -{ - return MMU_OPS.mrc (state, instr, value); -} - -void -mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) -{ - MMU_OPS.mcr (state, instr, value); -} - -/*ywc 20050416*/ -int -mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) -{ - return (MMU_OPS.v2p_dbct (state, virt_addr, phys_addr)); -} - -// -// -///* dis_mmu_read for disassemble */ -//exception_t arm_mmu_read(short size, uint32_t addr, uint32_t * value) -//{ -// ARMul_State *state; -// ARM_CPU_State *cpu = get_current_cpu(); -// state = &cpu->core[0]; -// switch(size){ -// case 8: -// MMU_OPS.read_byte (state, addr, value); -// break; -// case 16: -// case 32: -// break; -// default: -// ERROR_LOG(ARM11, "Error size %d", size); -// break; -// } -// return No_exp; -//} -///* dis_mmu_write for disassemble */ -//exception_t arm_mmu_write(short size, uint32_t addr, uint32_t *value) -//{ -// ARMul_State *state; -// ARM_CPU_State *cpu = get_current_cpu(); -// state = &cpu->core[0]; -// switch(size){ -// case 8: -// MMU_OPS.write_byte (state, addr, value); -// break; -// case 16: -// case 32: -// break; -// default: -// printf("In %s error size %d Line %d\n", __func__, size, __LINE__); -// break; -// } -// return No_exp; -//} diff --git a/src/core/arm/interpreter/armos.cpp b/src/core/arm/interpreter/armos.cpp deleted file mode 100644 index 43484ee5f..000000000 --- a/src/core/arm/interpreter/armos.cpp +++ /dev/null @@ -1,742 +0,0 @@ -/* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator. - Copyright (C) 1994 Advanced RISC Machines Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* This file contains a model of Demon, ARM Ltd's Debug Monitor, -including all the SWI's required to support the C library. The code in -it is not really for the faint-hearted (especially the abort handling -code), but it is a complete example. Defining NOOS will disable all the -fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI -0x11 to halt the emulator. */ - -//chy 2005-09-12 disable below line -//#include "config.h" - -#include <time.h> -#include <errno.h> -#include <string.h> -#include "skyeye_defs.h" -#ifndef __USE_LARGEFILE64 -#define __USE_LARGEFILE64 /* When use 64 bit large file need define it! for stat64*/ -#endif -#include <fcntl.h> -#include <sys/stat.h> - - -#ifndef O_RDONLY -#define O_RDONLY 0 -#endif -#ifndef O_WRONLY -#define O_WRONLY 1 -#endif -#ifndef O_RDWR -#define O_RDWR 2 -#endif -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifdef __STDC__ -#define unlink(s) remove(s) -#endif - -#ifdef HAVE_UNISTD_H -#include <unistd.h> /* For SEEK_SET etc */ -#endif - -#ifdef __riscos -extern int _fisatty (FILE *); -#define isatty_(f) _fisatty(f) -#else -#ifdef __ZTC__ -#include <io.h> -#define isatty_(f) isatty((f)->_file) -#else -#ifdef macintosh -#include <ioctl.h> -#define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL)) -#else -#define isatty_(f) isatty (fileno (f)) -#endif -#endif -#endif - -#include "armdefs.h" -#include "armos.h" -#include "armemu.h" - -#ifndef NOOS -#ifndef VALIDATE -/* #ifndef ASIM */ -//chy 2005-09-12 disable below line -//#include "armfpe.h" -/* #endif */ -#endif -#endif - -#define DUMP_SYSCALL 0 -#define dump(...) do { if (DUMP_SYSCALL) printf(__VA_ARGS__); } while(0) -//#define debug(...) printf(__VA_ARGS__); -#define debug(...) ; - -extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number); - -#ifndef FOPEN_MAX -#define FOPEN_MAX 64 -#endif - -/***************************************************************************\ -* OS private Information * -\***************************************************************************/ - -unsigned arm_dyncom_SWI(ARMul_State * state, ARMword number) -{ - return ARMul_OSHandleSWI(state, number); -} - -//mmap_area_t *mmap_global = NULL; - -static int translate_open_mode[] = { - O_RDONLY, /* "r" */ - O_RDONLY + O_BINARY, /* "rb" */ - O_RDWR, /* "r+" */ - O_RDWR + O_BINARY, /* "r+b" */ - O_WRONLY + O_CREAT + O_TRUNC, /* "w" */ - O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */ - O_RDWR + O_CREAT + O_TRUNC, /* "w+" */ - O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */ - O_WRONLY + O_APPEND + O_CREAT, /* "a" */ - O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */ - O_RDWR + O_APPEND + O_CREAT, /* "a+" */ - O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */ -}; -// -//static void -//SWIWrite0 (ARMul_State * state, ARMword addr) -//{ -// ARMword temp; -// -// //while ((temp = ARMul_ReadByte (state, addr++)) != 0) -// while(1){ -// mem_read(8, addr++, &temp); -// if(temp != 0) -// (void) fputc ((char) temp, stdout); -// else -// break; -// } -//} -// -//static void -//WriteCommandLineTo (ARMul_State * state, ARMword addr) -//{ -// ARMword temp; -// char *cptr = state->CommandLine; -// if (cptr == NULL) -// cptr = "\0"; -// do { -// temp = (ARMword) * cptr++; -// //ARMul_WriteByte (state, addr++, temp); -// mem_write(8, addr++, temp); -// } -// while (temp != 0); -//} -// -//static void -//SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags) -//{ -// char dummy[2000]; -// int flags; -// int i; -// -// for (i = 0; (dummy[i] = ARMul_ReadByte (state, name + i)); i++); -// assert(SWIflags< (sizeof(translate_open_mode)/ sizeof(translate_open_mode[0]))); -// /* Now we need to decode the Demon open mode */ -// flags = translate_open_mode[SWIflags]; -// flags = SWIflags; -// -// /* Filename ":tt" is special: it denotes stdin/out */ -// if (strcmp (dummy, ":tt") == 0) { -// if (flags == O_RDONLY) /* opening tty "r" */ -// state->Reg[0] = 0; /* stdin */ -// else -// state->Reg[0] = 1; /* stdout */ -// } -// else { -// state->Reg[0] = (int) open (dummy, flags, 0666); -// } -//} -// -//static void -//SWIread (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) -//{ -// int res; -// int i; -// char *local = (char*) malloc (len); -// -// if (local == NULL) { -// fprintf (stderr, -// "sim: Unable to read 0x%ulx bytes - out of memory\n", -// len); -// return; -// } -// -// res = read (f, local, len); -// if (res > 0) -// for (i = 0; i < res; i++) -// //ARMul_WriteByte (state, ptr + i, local[i]); -// mem_write(8, ptr + i, local[i]); -// free (local); -// //state->Reg[0] = res == -1 ? -1 : len - res; -// state->Reg[0] = res; -//} -// -//static void -//SWIwrite (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) -//{ -// int res; -// ARMword i; -// char *local = malloc (len); -// -// if (local == NULL) { -// fprintf (stderr, -// "sim: Unable to write 0x%lx bytes - out of memory\n", -// (long unsigned int) len); -// return; -// } -// -// for (i = 0; i < len; i++){ -// //local[i] = ARMul_ReadByte (state, ptr + i); -// ARMword data; -// mem_read(8, ptr + i, &data); -// local[i] = data & 0xFF; -// } -// -// res = write (f, local, len); -// //state->Reg[0] = res == -1 ? -1 : len - res; -// state->Reg[0] = res; -// free (local); -//} - -//static void -//SWIflen (ARMul_State * state, ARMword fh) -//{ -// ARMword addr; -// -// if (fh == 0 || fh > FOPEN_MAX) { -// state->Reg[0] = -1L; -// return; -// } -// -// addr = lseek (fh, 0, SEEK_CUR); -// -// state->Reg[0] = lseek (fh, 0L, SEEK_END); -// (void) lseek (fh, addr, SEEK_SET); -// -//} - -/***************************************************************************\ -* The emulator calls this routine when a SWI instruction is encuntered. The * -* parameter passed is the SWI number (lower 24 bits of the instruction). * -\***************************************************************************/ -/* ahe-ykl information is retrieved from elf header and the starting value of - brk_static is in sky_info_t */ - -/* brk static hold the value of brk */ -static uint32_t brk_static = -1; - -unsigned -ARMul_OSHandleSWI (ARMul_State * state, ARMword number) -{ - number &= 0xfffff; - ARMword addr, temp; - - switch (number) { -// case SWI_Syscall: -// if (state->Reg[7] != 0) -// return ARMul_OSHandleSWI(state, state->Reg[7]); -// else -// return FALSE; -// case SWI_Read: -// SWIread (state, state->Reg[0], state->Reg[1], state->Reg[2]); -// return TRUE; -// -// case SWI_GetUID32: -// state->Reg[0] = getuid(); -// return TRUE; -// -// case SWI_GetGID32: -// state->Reg[0] = getgid(); -// return TRUE; -// -// case SWI_GetEUID32: -// state->Reg[0] = geteuid(); -// return TRUE; -// -// case SWI_GetEGID32: -// state->Reg[0] = getegid(); -// return TRUE; -// -// case SWI_Write: -// SWIwrite (state, state->Reg[0], state->Reg[1], state->Reg[2]); -// return TRUE; -// -// case SWI_Open: -// SWIopen (state, state->Reg[0], state->Reg[1]); -// return TRUE; -// -// case SWI_Close: -// state->Reg[0] = close (state->Reg[0]); -// return TRUE; -// -// case SWI_Seek:{ -// /* We must return non-zero for failure */ -// state->Reg[0] = -// lseek (state->Reg[0], state->Reg[1], -// SEEK_SET); -// return TRUE; -// } -// -// case SWI_ExitGroup: -// case SWI_Exit: -// { -// struct timeval tv; -// //gettimeofday(&tv,NULL); -// //printf("In %s, %d sec, %d usec\n", __FUNCTION__, tv.tv_sec, tv.tv_usec); -// printf("passed %d sec, %lld usec\n", get_clock_sec(), get_clock_us()); -// -// /* quit here */ -// run_command("quit"); -// return TRUE; -// } -// case SWI_Times:{ -// uint32_t dest = state->Reg[0]; -// struct tms now; -// struct target_tms32 nowret; -// -// uint32_t ret = times(&now); -// -// if (ret == -1){ -// debug("syscall %s error %d\n", "SWI_Times", ret); -// state->Reg[0] = ret; -// return FALSE; -// } -// -// nowret.tms_cstime = now.tms_cstime; -// nowret.tms_cutime = now.tms_cutime; -// nowret.tms_stime = now.tms_stime; -// nowret.tms_utime = now.tms_utime; -// -// uint32_t offset; -// for (offset = 0; offset < sizeof(nowret); offset++) { -// bus_write(8, dest + offset, *((uint8_t *) &nowret + offset)); -// } -// -// state->Reg[0] = ret; -// return TRUE; -// } -// -// case SWI_Gettimeofday: { -// uint32_t dest1 = state->Reg[0]; -// uint32_t dest2 = state->Reg[1]; // Unsure of this -// struct timeval val; -// struct timezone zone; -// struct target_timeval32 valret; -// struct target_timezone32 zoneret; -// -// uint32_t ret = gettimeofday(&val, &zone); -// valret.tv_sec = val.tv_sec; -// valret.tv_usec = val.tv_usec; -// zoneret.tz_dsttime = zoneret.tz_dsttime; -// zoneret.tz_minuteswest = zoneret.tz_minuteswest; -// -// if (ret == -1){ -// debug("syscall %s error %d\n", "SWI_Gettimeofday", ret); -// state->Reg[0] = ret; -// return FALSE; -// } -// -// uint32_t offset; -// if (dest1) { -// for (offset = 0; offset < sizeof(valret); offset++) { -// bus_write(8, dest1 + offset, *((uint8_t *) &valret + offset)); -// } -// state->Reg[0] = ret; -// } -// if (dest2) { -// for (offset = 0; offset < sizeof(zoneret); offset++) { -// bus_write(8, dest2 + offset, *((uint8_t *) &zoneret + offset)); -// } -// state->Reg[0] = ret; -// } -// -// return TRUE; -// } -// case SWI_Brk: -// /* initialize brk value */ -// /* suppose that brk_static doesn't reach 0xffffffff... */ -// if (brk_static == -1) { -// brk_static = (get_skyeye_pref()->info).brk; -// } -// -// /* FIXME there might be a need to do a mmap */ -// -// if(state->Reg[0]){ -// if (get_skyeye_exec_info()->mmap_access) { -// /* if new brk is greater than current brk, allocate memory */ -// if (state->Reg[0] > brk_static) { -// uint32_t ret = mmap( (void *) brk_static, state->Reg[0] - brk_static, -// PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0 ); -// if (ret != MAP_FAILED) -// brk_static = ret; -// } -// } -// brk_static = state->Reg[0]; -// //state->Reg[0] = 0; /* FIXME return value of brk set to be the address on success */ -// } else { -// state->Reg[0] = brk_static; -// } -// return TRUE; -// -// case SWI_Break: -// state->Emulate = FALSE; -// return TRUE; -// -// case SWI_Mmap:{ -// int addr = state->Reg[0]; -// int len = state->Reg[1]; -// int prot = state->Reg[2]; -// int flag = state->Reg[3]; -// int fd = state->Reg[4]; -// int offset = state->Reg[5]; -// mmap_area_t *area = new_mmap_area(addr, len); -// state->Reg[0] = area->bank.addr; -// //printf("syscall %d mmap(0x%x,%x,0x%x,0x%x,%d,0x%x) = 0x%x\n",\ -// SWI_Mmap, addr, len, prot, flag, fd, offset, state->Reg[0]); -// return TRUE; -// } -// -// case SWI_Munmap: -// state->Reg[0] = 0; -// return TRUE; -// -// case SWI_Mmap2:{ -// int addr = state->Reg[0]; -// int len = state->Reg[1]; -// int prot = state->Reg[2]; -// int flag = state->Reg[3]; -// int fd = state->Reg[4]; -// int offset = state->Reg[5] * 4096; /* page offset */ -// mmap_area_t *area = new_mmap_area(addr, len); -// state->Reg[0] = area->bank.addr; -// -// return TRUE; -// } -// -// case SWI_Breakpoint: -// //chy 2005-09-12 change below line -// //state->EndCondition = RDIError_BreakpointReached; -// //printf ("SKYEYE: in armos.c : should not come here!!!!\n"); -// state->EndCondition = 0; -// /*modified by ksh to support breakpoiont*/ -// state->Emulate = STOP; -// return (TRUE); -// case SWI_Uname: -// { -// struct utsname *uts = (uintptr_t) state->Reg[0]; /* uname should write data in this address */ -// struct utsname utsbuf; -// //printf("Uname size is %x\n", sizeof(utsbuf)); -// char *buf; -// uintptr_t sp ; /* used as a temporary address */ -// -//#define COPY_UTS_STRING(addr) \ -// buf = addr; \ -// while(*buf != NULL) { \ -// bus_write(8, sp, *buf); \ -// sp++; \ -// buf++; \ -// } -//#define COPY_UTS(field) /*printf("%s: %s at %p\n", #field, utsbuf.field, uts->field);*/ \ -// sp = (uintptr_t) uts->field; \ -// COPY_UTS_STRING((&utsbuf)->field); -// -// if (uname(&utsbuf) < 0) { -// printf("syscall uname: utsname error\n"); -// state->Reg[0] = -1; -// return FALSE; -// } -// -// /* FIXME for now, this is just the host system call -// Some data should be missing, as it depends on -// the version of utsname */ -// COPY_UTS(sysname); -// COPY_UTS(nodename); -// COPY_UTS(release); -// COPY_UTS(version); -// COPY_UTS(machine); -// -// state->Reg[0] = 0; -// return TRUE; -// } -// case SWI_Fcntl: -// { -// uint32_t fd = state->Reg[0]; -// uint32_t cmd = state->Reg[1]; -// uint32_t arg = state->Reg[2]; -// uint32_t ret; -// -// switch(cmd){ -// case (F_GETFD): -// { -// ret = fcntl(fd, cmd, arg); -// //printf("syscall fcntl for getfd not implemented, ret %d\n", ret); -// state->Reg[0] = ret; -// return FALSE; -// } -// default: -// break; -// } -// -// printf("syscall fcntl unimplemented fd %x cmd %x\n", fd, cmd); -// state->Reg[0] = -1; -// return FALSE; -// -// } -// case SWI_Fstat64: -// { -// uint32_t dest = state->Reg[1]; -// uint32_t fd = state->Reg[0]; -// struct stat64 statbuf; -// struct target_stat64 statret; -// memset(&statret, 0, sizeof(struct target_stat64)); -// uint32_t ret = fstat64(fd, &statbuf); -// -// if (ret == -1){ -// printf("syscall %s returned error\n", "SWI_Fstat"); -// state->Reg[0] = ret; -// return FALSE; -// } -// -// /* copy statbuf to the process memory space -// FIXME can't say if endian has an effect here */ -// uint32_t offset; -// //printf("Fstat system is size %x\n", sizeof(statbuf)); -// //printf("Fstat target is size %x\n", sizeof(statret)); -// -// /* we copy system structure data stat64 into arm fixed size structure target_stat64 */ -// statret.st_dev = statbuf.st_dev; -// statret.st_ino = statbuf.st_ino; -// statret.st_mode = statbuf.st_mode; -// statret.st_nlink = statbuf.st_nlink; -// statret.st_uid = statbuf.st_uid; -// statret.st_gid = statbuf.st_gid; -// statret.st_rdev = statbuf.st_rdev; -// statret.st_size = statbuf.st_size; -// statret.st_blksize = statbuf.st_blksize; -// statret.st_blocks = statbuf.st_blocks; -// statret.st32_atime = statbuf.st_atime; -// statret.st32_mtime = statbuf.st_mtime; -// statret.st32_ctime = statbuf.st_ctime; -// -// for (offset = 0; offset < sizeof(statret); offset++) { -// bus_write(8, dest + offset, *((uint8_t *) &statret + offset)); -// } -// -// state->Reg[0] = ret; -// return TRUE; -// } -// case SWI_Set_tls: -// { -// //printf("syscall set_tls unimplemented\n"); -// state->mmu.thread_uro_id = state->Reg[0]; -// state->CP15[CP15_THREAD_URO - CP15_BASE] = state->Reg[0]; -// state->Reg[0] = 0; -// return FALSE; -// } -//#if 0 -// case SWI_Clock: -// /* return number of centi-seconds... */ -// state->Reg[0] = -//#ifdef CLOCKS_PER_SEC -// (CLOCKS_PER_SEC >= 100) -// ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100)) -// : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC); -//#else -// /* presume unix... clock() returns microseconds */ -// (ARMword) (clock () / 10000); -//#endif -// return (TRUE); -// -// case SWI_Time: -// state->Reg[0] = (ARMword) time (NULL); -// return (TRUE); -// case SWI_Flen: -// SWIflen (state, state->Reg[0]); -// return (TRUE); -// -//#endif - default: - - _dbg_assert_msg_(ARM11, false, "ImplementMe: ARMul_OSHandleSWI!"); - - return (FALSE); - } -} -// -///** -// * @brief For mmap syscall.A mmap_area is a memory bank. Get from ppc. -// */ -//static mmap_area_t* new_mmap_area(int sim_addr, int len){ -// mmap_area_t *area = (mmap_area_t *)malloc(sizeof(mmap_area_t)); -// if(area == NULL){ -// printf("error, failed %s\n",__FUNCTION__); -// exit(0); -// } -//#if FAST_MEMORY -// if (mmap_next_base == -1) -// { -// mmap_next_base = get_skyeye_exec_info()->brk; -// } -//#endif -// -// memset(area, 0x0, sizeof(mmap_area_t)); -// area->bank.addr = mmap_next_base; -// area->bank.len = len; -// area->bank.bank_write = mmap_mem_write; -// area->bank.bank_read = mmap_mem_read; -// area->bank.type = MEMTYPE_RAM; -// area->bank.objname = "mmap"; -// addr_mapping(&area->bank); -// -//#if FAST_MEMORY -// if (get_skyeye_exec_info()->mmap_access) -// { -// /* FIXME check proper flags */ -// /* FIXME we may delete the need of banks up there */ -// uint32_t ret = mmap(mmap_next_base, len, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -// mmap_next_base = ret; -// } -// area->mmap_addr = (uint8_t*)get_dma_addr(mmap_next_base); -//#else -// area->mmap_addr = malloc(len); -// if(area->mmap_addr == NULL){ -// printf("error mmap malloc\n"); -// exit(0); -// } -// memset(area->mmap_addr, 0x0, len); -//#endif -// -// area->next = NULL; -// if(mmap_global){ -// area->next = mmap_global->next; -// mmap_global->next = area; -// }else{ -// mmap_global = area; -// } -// mmap_next_base = mmap_next_base + len; -// return area; -//} -// -//static mmap_area_t *get_mmap_area(int addr){ -// mmap_area_t *tmp = mmap_global; -// while(tmp){ -// if ((tmp->bank.addr <= addr) && (tmp->bank.addr + tmp->bank.len > addr)){ -// return tmp; -// } -// tmp = tmp->next; -// } -// printf("cannot get mmap area:addr=0x%x\n", addr); -// return NULL; -//} -// -///** -// * @brief the mmap_area bank write function. Get from ppc. -// * -// * @param size size to write, 8/16/32 -// * @param addr address to write -// * @param value value to write -// * -// * @return sucess return 1,otherwise 0. -// */ -//static char mmap_mem_write(short size, int addr, uint32_t value){ -// mmap_area_t *area_tmp = get_mmap_area(addr); -// mem_bank_t *bank_tmp = &area_tmp->bank; -// int offset = addr - bank_tmp->addr; -// switch(size){ -// case 8:{ -// //uint8_t value_endian = value; -// uint8_t value_endian = (uint8_t)value; -// *(uint8_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); -// break; -// } -// case 16:{ -// //uint16_t value_endian = half_to_BE((uint16_t)value); -// uint16_t value_endian = ((uint16_t)value); -// *(uint16_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); -// break; -// } -// case 32:{ -// //uint32_t value_endian = word_to_BE((uint32_t)value); -// uint32_t value_endian = ((uint32_t)value); -// *(uint32_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); -// break; -// } -// default: -// printf("invalid size %d\n",size); -// return 0; -// } -// return 1; -//} -// -///** -// * @brief the mmap_area bank read function. Get from ppc. -// * -// * @param size size to read, 8/16/32 -// * @param addr address to read -// * @param value value to read -// * -// * @return sucess return 1,otherwise 0. -// */ -//static char mmap_mem_read(short size, int addr, uint32_t * value){ -// mmap_area_t *area_tmp = get_mmap_area(addr); -// mem_bank_t *bank_tmp = &area_tmp->bank; -// int offset = addr - bank_tmp->addr; -// switch(size){ -// case 8:{ -// //*(uint8_t *)value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); -// *value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); -// break; -// } -// case 16:{ -// //*(uint16_t *)value = half_from_BE(*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); -// *value = (*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint16_t*)value); -// break; -// } -// case 32: -// //*value = (uint32_t)word_from_BE(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); -// *value = (uint32_t)(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); -// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); -// break; -// default: -// printf("invalid size %d\n",size); -// return 0; -// } -// return 1; -//} diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index 3d3545c65..2568b93ef 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -15,18 +15,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -//#include <util.h> - -#include <string> -#include "core/arm/interpreter/armdefs.h" -#include "core/arm/interpreter/armemu.h" -#include "core/hle/coprocessor.h" +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/armemu.h" #include "core/arm/disassembler/arm_disasm.h" +#include "core/mem_map.h" -//#include "ansidecl.h" -//#include "skyeye.h" -//extern int skyeye_instr_debug; -/* Definitions for the support routines. */ static ARMword ModeToBank (ARMword); static void EnvokeList (ARMul_State *, unsigned int, unsigned int); @@ -751,7 +744,7 @@ ARMword ARMul_MRC (ARMul_State * state, ARMword instr) int cpopc = BITS(21, 23) & 0x7; if (cn == 13 && cm == 0 && cp == 3) { //c13,c0,3; returns CPU svc buffer - ARMword result = HLE::CallMRC(instr); + ARMword result = Memory::KERNEL_MEMORY_VADDR; if (result != -1) { return result; diff --git a/src/core/arm/interpreter/armvirt.cpp b/src/core/arm/interpreter/armvirt.cpp index a072b73be..7845d1042 100644 --- a/src/core/arm/interpreter/armvirt.cpp +++ b/src/core/arm/interpreter/armvirt.cpp @@ -23,658 +23,143 @@ table. The routines PutWord and GetWord implement this. Pages are never freed as they might be needed again. A single area of memory may be defined to generate aborts. */ -#include "armdefs.h" -#include "skyeye_defs.h" -//#include "code_cov.h" +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/armemu.h" -#ifdef VALIDATE /* for running the validate suite */ -#define TUBE 48 * 1024 * 1024 /* write a char on the screen */ -#define ABORTS 1 -#endif - -/* #define ABORTS */ - -#ifdef ABORTS /* the memory system will abort */ -/* For the old test suite Abort between 32 Kbytes and 32 Mbytes - For the new test suite Abort between 8 Mbytes and 26 Mbytes */ -/* #define LOWABORT 32 * 1024 -#define HIGHABORT 32 * 1024 * 1024 */ -#define LOWABORT 8 * 1024 * 1024 -#define HIGHABORT 26 * 1024 * 1024 - -#endif - -#define NUMPAGES 64 * 1024 -#define PAGESIZE 64 * 1024 -#define PAGEBITS 16 -#define OFFSETBITS 0xffff -//chy 2003-08-19: seems no use ???? -int SWI_vector_installed = FALSE; -extern ARMword skyeye_cachetype; - -/***************************************************************************\ -* Get a byte into Virtual Memory, maybe allocating the page * -\***************************************************************************/ -static fault_t -GetByte (ARMul_State * state, ARMword address, ARMword * data) -{ - fault_t fault; - - fault = mmu_read_byte (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -// printf("SKYEYE: GetByte fault %d \n", fault); - } - return fault; -} - -/***************************************************************************\ -* Get a halfword into Virtual Memory, maybe allocating the page * -\***************************************************************************/ -static fault_t -GetHalfWord (ARMul_State * state, ARMword address, ARMword * data) -{ - fault_t fault; - - fault = mmu_read_halfword (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -// printf("SKYEYE: GetHalfWord fault %d \n", fault); - } - return fault; -} - -/***************************************************************************\ -* Get a Word from Virtual Memory, maybe allocating the page * -\***************************************************************************/ +#include "core/mem_map.h" -static fault_t -GetWord (ARMul_State * state, ARMword address, ARMword * data) -{ - fault_t fault; +#define dumpstack 1 +#define dumpstacksize 0x10 +#define maxdmupaddr 0x0033a850 - fault = mmu_read_word (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -#if 0 -/* XXX */ extern int hack; - hack = 1; -#endif -#if 0 - printf ("mmu_read_word at 0x%08x: ", address); - switch (fault) { - case ALIGNMENT_FAULT: - printf ("ALIGNMENT_FAULT"); - break; - case SECTION_TRANSLATION_FAULT: - printf ("SECTION_TRANSLATION_FAULT"); - break; - case PAGE_TRANSLATION_FAULT: - printf ("PAGE_TRANSLATION_FAULT"); - break; - case SECTION_DOMAIN_FAULT: - printf ("SECTION_DOMAIN_FAULT"); - break; - case SECTION_PERMISSION_FAULT: - printf ("SECTION_PERMISSION_FAULT"); - break; - case SUBPAGE_PERMISSION_FAULT: - printf ("SUBPAGE_PERMISSION_FAULT"); - break; - default: - printf ("Unrecognized fault number!"); - } - printf ("\tpc = 0x%08x\n", state->Reg[15]); -#endif - } - return fault; +/*ARMword ARMul_GetCPSR (ARMul_State * state) { +return 0; } - -//2003-07-10 chy: lyh change -/****************************************************************************\ - * Load a Instrion Word into Virtual Memory * -\****************************************************************************/ -static fault_t -LoadInstr (ARMul_State * state, ARMword address, ARMword * instr) -{ - fault_t fault; - fault = mmu_load_instr (state, address, instr); - return fault; - //if (fault) - // log_msg("load_instr fault = %d, address = %x\n", fault, address); +ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode) { +return 0; } +void ARMul_SetCPSR (ARMul_State * state, ARMword value) { -/***************************************************************************\ -* Put a byte into Virtual Memory, maybe allocating the page * -\***************************************************************************/ -static fault_t -PutByte (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - - fault = mmu_write_byte (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -// printf("SKYEYE: PutByte fault %d \n", fault); - } - return fault; } +void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) { -/***************************************************************************\ -* Put a halfword into Virtual Memory, maybe allocating the page * -\***************************************************************************/ -static fault_t -PutHalfWord (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; +}*/ - fault = mmu_write_halfword (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -// printf("SKYEYE: PutHalfWord fault %d \n", fault); - } - return fault; +void ARMul_Icycles(ARMul_State * state, unsigned number, ARMword address) { } -/***************************************************************************\ -* Put a Word into Virtual Memory, maybe allocating the page * -\***************************************************************************/ - -static fault_t -PutWord (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - - fault = mmu_write_word (state, address, data); - if (fault) { -//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? -#if 0 -/* XXX */ extern int hack; - hack = 1; -#endif -#if 0 - printf ("mmu_write_word at 0x%08x: ", address); - switch (fault) { - case ALIGNMENT_FAULT: - printf ("ALIGNMENT_FAULT"); - break; - case SECTION_TRANSLATION_FAULT: - printf ("SECTION_TRANSLATION_FAULT"); - break; - case PAGE_TRANSLATION_FAULT: - printf ("PAGE_TRANSLATION_FAULT"); - break; - case SECTION_DOMAIN_FAULT: - printf ("SECTION_DOMAIN_FAULT"); - break; - case SECTION_PERMISSION_FAULT: - printf ("SECTION_PERMISSION_FAULT"); - break; - case SUBPAGE_PERMISSION_FAULT: - printf ("SUBPAGE_PERMISSION_FAULT"); - break; - default: - printf ("Unrecognized fault number!"); - } - printf ("\tpc = 0x%08x\n", state->Reg[15]); -#endif - } - return fault; +void ARMul_Ccycles(ARMul_State * state, unsigned number, ARMword address) { } -/***************************************************************************\ -* Initialise the memory interface * -\***************************************************************************/ - -unsigned -ARMul_MemoryInit (ARMul_State * state, unsigned int initmemsize) -{ - return TRUE; -} - -/***************************************************************************\ -* Remove the memory interface * -\***************************************************************************/ - -void -ARMul_MemoryExit (ARMul_State * state) -{ -} - -/***************************************************************************\ -* ReLoad Instruction * -\***************************************************************************/ - -ARMword -ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize) -{ - ARMword data; - fault_t fault; - -#ifdef ABORTS - if (address >= LOWABORT && address < HIGHABORT) { - ARMul_PREFETCHABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } -#endif -#if 0 - /* do profiling for code coverage */ - if (skyeye_config.code_cov.prof_on) - cov_prof(EXEC_FLAG, address); -#endif -#if 1 - if ((isize == 2) && (address & 0x2)) { - ARMword lo, hi; - if (!(skyeye_cachetype == INSTCACHE)) - fault = GetHalfWord (state, address, &lo); - else - fault = LoadInstr (state, address, &lo); -#if 0 - if (!fault) { - if (!(skyeye_cachetype == INSTCACHE)) - fault = GetHalfWord (state, address + isize, &hi); - else - fault = LoadInstr (state, address + isize, &hi); - - } -#endif - if (fault) { - ARMul_PREFETCHABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - return lo; -#if 0 - if (state->bigendSig == HIGH) - return (lo << 16) | (hi >> 16); - else - return ((hi & 0xFFFF) << 16) | (lo >> 16); -#endif - } -#endif - if (!(skyeye_cachetype == INSTCACHE)) - fault = GetWord (state, address, &data); - else - fault = LoadInstr (state, address, &data); - - if (fault) { - - /* dyf add for s3c6410 no instcache temporary 2010.9.17 */ - if (!(skyeye_cachetype == INSTCACHE)) { - /* set translation fault on prefetch abort */ - state->mmu.fault_statusi = fault & 0xFF; - state->mmu.fault_address = address; - } - /* add end */ - - ARMul_PREFETCHABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - - return data; -} - -/***************************************************************************\ -* Load Instruction, Sequential Cycle * -\***************************************************************************/ - -ARMword -ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize) -{ - state->NumScycles++; +ARMword ARMul_LoadInstrS(ARMul_State * state, ARMword address, ARMword isize) { + state->NumScycles++; #ifdef HOURGLASS - if ((state->NumScycles & HOURGLASS_RATE) == 0) { - HOURGLASS; - } + if ((state->NumScycles & HOURGLASS_RATE) == 0) { + HOURGLASS; + } #endif - - return ARMul_ReLoadInstr (state, address, isize); + if (isize == 2) + return (u16)Memory::Read16(address); + else + return (u32)Memory::Read32(address); } -/***************************************************************************\ -* Load Instruction, Non Sequential Cycle * -\***************************************************************************/ - -ARMword -ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize) -{ - state->NumNcycles++; +ARMword ARMul_LoadInstrN(ARMul_State * state, ARMword address, ARMword isize) { + state->NumNcycles++; - return ARMul_ReLoadInstr (state, address, isize); + if (isize == 2) + return (u16)Memory::Read16(address); + else + return (u32)Memory::Read32(address); } -/***************************************************************************\ -* Read Word (but don't tell anyone!) * -\***************************************************************************/ +ARMword ARMul_ReLoadInstr(ARMul_State * state, ARMword address, ARMword isize) { + ARMword data; -ARMword -ARMul_ReadWord (ARMul_State * state, ARMword address) -{ - ARMword data; - fault_t fault; - -#ifdef ABORTS - if (address >= LOWABORT && address < HIGHABORT) { - ARMul_DATAABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } -#endif + if ((isize == 2) && (address & 0x2)) { + ARMword lo; + lo = (u16)Memory::Read16(address); + return lo; + } - fault = GetWord (state, address, &data); - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - return data; + data = (u32)Memory::Read32(address); + return data; } -/***************************************************************************\ -* Load Word, Sequential Cycle * -\***************************************************************************/ - -ARMword -ARMul_LoadWordS (ARMul_State * state, ARMword address) -{ - state->NumScycles++; - - return ARMul_ReadWord (state, address); +ARMword ARMul_ReadWord(ARMul_State * state, ARMword address) { + ARMword data; + data = Memory::Read32(address); + return data; } -/***************************************************************************\ -* Load Word, Non Sequential Cycle * -\***************************************************************************/ - -ARMword -ARMul_LoadWordN (ARMul_State * state, ARMword address) -{ - state->NumNcycles++; - - return ARMul_ReadWord (state, address); +ARMword ARMul_LoadWordS(ARMul_State * state, ARMword address) { + state->NumScycles++; + return ARMul_ReadWord(state, address); } -/***************************************************************************\ -* Load Halfword, (Non Sequential Cycle) * -\***************************************************************************/ - -ARMword -ARMul_LoadHalfWord (ARMul_State * state, ARMword address) -{ - ARMword data; - fault_t fault; - - state->NumNcycles++; - fault = GetHalfWord (state, address, &data); - - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - - return data; - +ARMword ARMul_LoadWordN(ARMul_State * state, ARMword address) { + state->NumNcycles++; + return ARMul_ReadWord(state, address); } -/***************************************************************************\ -* Read Byte (but don't tell anyone!) * -\***************************************************************************/ -int ARMul_ICE_ReadByte(ARMul_State * state, ARMword address, ARMword *presult) -{ - ARMword data; - fault_t fault; - fault = GetByte (state, address, &data); - if (fault) { - *presult=-1; fault=ALIGNMENT_FAULT; return fault; - }else{ - *(char *)presult=(unsigned char)(data & 0xff); fault=NO_FAULT; return fault; - } +ARMword ARMul_LoadHalfWord(ARMul_State * state, ARMword address) { + state->NumNcycles++; + return (u16)Memory::Read16(address);; } - - -ARMword -ARMul_ReadByte (ARMul_State * state, ARMword address) -{ - ARMword data; - fault_t fault; - - fault = GetByte (state, address, &data); - - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return ARMul_ABORTWORD; - } - else { - ARMul_CLEARABORT; - } - - return data; - -} - -/***************************************************************************\ -* Load Byte, (Non Sequential Cycle) * -\***************************************************************************/ - -ARMword -ARMul_LoadByte (ARMul_State * state, ARMword address) -{ - state->NumNcycles++; - - return ARMul_ReadByte (state, address); -} - -/***************************************************************************\ -* Write Word (but don't tell anyone!) * -\***************************************************************************/ - -void -ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - -#ifdef ABORTS - if (address >= LOWABORT && address < HIGHABORT) { - ARMul_DATAABORT (address); - return; - } - else { - ARMul_CLEARABORT; - } -#endif - fault = PutWord (state, address, data); - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return; - } - else { - ARMul_CLEARABORT; - } +ARMword ARMul_ReadByte(ARMul_State * state, ARMword address) { + return (u8)Memory::Read8(address); } -/***************************************************************************\ -* Store Word, Sequential Cycle * -\***************************************************************************/ - -void -ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data) -{ - state->NumScycles++; - - ARMul_WriteWord (state, address, data); +ARMword ARMul_LoadByte(ARMul_State * state, ARMword address) { + state->NumNcycles++; + return ARMul_ReadByte(state, address); } -/***************************************************************************\ -* Store Word, Non Sequential Cycle * -\***************************************************************************/ - -void -ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data) -{ - state->NumNcycles++; - - ARMul_WriteWord (state, address, data); +void ARMul_StoreHalfWord(ARMul_State * state, ARMword address, ARMword data) { + state->NumNcycles++; + Memory::Write16(address, data); } -/***************************************************************************\ -* Store HalfWord, (Non Sequential Cycle) * -\***************************************************************************/ - -void -ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - state->NumNcycles++; - fault = PutHalfWord (state, address, data); - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return; - } - else { - ARMul_CLEARABORT; - } +void ARMul_StoreByte(ARMul_State * state, ARMword address, ARMword data) { + state->NumNcycles++; + ARMul_WriteByte(state, address, data); } -//chy 2006-04-15 -int ARMul_ICE_WriteByte (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - fault = PutByte (state, address, data); - if (fault) - return 1; - else - return 0; -} -/***************************************************************************\ -* Write Byte (but don't tell anyone!) * -\***************************************************************************/ -//chy 2003-07-10, add real write byte fun -void -ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data) -{ - fault_t fault; - fault = PutByte (state, address, data); - if (fault) { - state->mmu.fault_status = - (fault | (state->mmu.last_domain << 4)) & 0xFF; - state->mmu.fault_address = address; - ARMul_DATAABORT (address); - return; - } - else { - ARMul_CLEARABORT; - } +ARMword ARMul_SwapWord(ARMul_State * state, ARMword address, ARMword data) { + ARMword temp; + state->NumNcycles++; + temp = ARMul_ReadWord(state, address); + state->NumNcycles++; + Memory::Write32(address, data); + return temp; } -/***************************************************************************\ -* Store Byte, (Non Sequential Cycle) * -\***************************************************************************/ - -void -ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data) -{ - state->NumNcycles++; - -#ifdef VALIDATE - if (address == TUBE) { - if (data == 4) - state->Emulate = FALSE; - else - (void) putc ((char) data, stderr); /* Write Char */ - return; - } -#endif - - ARMul_WriteByte (state, address, data); +ARMword ARMul_SwapByte(ARMul_State * state, ARMword address, ARMword data) { + ARMword temp; + temp = ARMul_LoadByte(state, address); + Memory::Write8(address, data); + return temp; } -/***************************************************************************\ -* Swap Word, (Two Non Sequential Cycles) * -\***************************************************************************/ - -ARMword -ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data) -{ - ARMword temp; - - state->NumNcycles++; - - temp = ARMul_ReadWord (state, address); - - state->NumNcycles++; - - PutWord (state, address, data); - - return temp; +void ARMul_WriteWord(ARMul_State * state, ARMword address, ARMword data) { + Memory::Write32(address, data); } -/***************************************************************************\ -* Swap Byte, (Two Non Sequential Cycles) * -\***************************************************************************/ - -ARMword -ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data) +void ARMul_WriteByte(ARMul_State * state, ARMword address, ARMword data) { - ARMword temp; - - temp = ARMul_LoadByte (state, address); - ARMul_StoreByte (state, address, data); - - return temp; + Memory::Write8(address, data); } -/***************************************************************************\ -* Count I Cycles * -\***************************************************************************/ - -void -ARMul_Icycles (ARMul_State * state, unsigned number, - ARMword address) +void ARMul_StoreWordS(ARMul_State * state, ARMword address, ARMword data) { - state->NumIcycles += number; - ARMul_CLEARABORT; + state->NumScycles++; + ARMul_WriteWord(state, address, data); } -/***************************************************************************\ -* Count C Cycles * -\***************************************************************************/ - -void -ARMul_Ccycles (ARMul_State * state, unsigned number, - ARMword address) +void ARMul_StoreWordN(ARMul_State * state, ARMword address, ARMword data) { - state->NumCcycles += number; - ARMul_CLEARABORT; + state->NumNcycles++; + ARMul_WriteWord(state, address, data); } diff --git a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp deleted file mode 100644 index a32f076b9..000000000 --- a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.cpp +++ /dev/null @@ -1,1132 +0,0 @@ -/* - arm1176jzf_s_mmu.c - ARM920T Memory Management Unit emulation. - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to <skyeye-developer@lists.gro.clinux.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <assert.h> -#include <string.h> -#include <stdint.h> - -#include "core/mem_map.h" - -#include "core/arm/interpreter/skyeye_defs.h" - -#include "core/arm/interpreter/armdefs.h" -//#include "bank_defs.h" -#if 0 -#define TLB_SIZE 1024 * 1024 -#define ASID 255 -static uint32_t tlb_entry_array[TLB_SIZE][ASID]; -static inline void invalidate_all_tlb(ARMul_State *state){ - memset(&tlb_entry_array[0], 0xFF, sizeof(uint32_t) * TLB_SIZE * ASID); -} -static inline void invalidate_by_mva(ARMul_State *state, ARMword va){ - memset(&tlb_entry_array[va >> 12][va & 0xFF], 0xFF, sizeof(uint32_t)); - return; -} -static inline void invalidate_by_asid(ARMul_State *state, ARMword asid){ - int i; - for(i = 0; i < TLB_SIZE; i++) - memset(&tlb_entry_array[i][asid & 0xFF], 0xFF, sizeof(uint32_t)); - return; -} - -static uint32_t get_phys_page(ARMul_State* state, ARMword va){ - uint32_t phys_page = tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF]; - //printf("In %s, for va=0x%x, page=0x%x\n", __func__, va, phys_page); - return phys_page; -} - -static inline void insert_tlb(ARMul_State* state, ARMword va, ARMword pa){ - //printf("In %s, insert va=0x%x, pa=0x%x\n", __FUNCTION__, va, pa); - //printf("In %s, insert va=0x%x, va>>12=0x%x, pa=0x%x, pa>>12=0x%x\n", __FUNCTION__, va, va >> 12, pa, pa >> 12); - tlb_entry_array[va >> 12][state->mmu.context_id & 0xFF] = pa >> 12; - - return; -} -#endif -#define BANK0_START 0x50000000 -static void* mem_ptr = NULL; - -static int exclusive_detect(ARMul_State* state, ARMword addr){ - #if 0 - for(int i = 0; i < 128; i++){ - if(state->exclusive_tag_array[i] == addr) - return 0; - } - #endif - if(state->exclusive_tag_array[0] == addr) - return 0; - else - return -1; -} - -static void add_exclusive_addr(ARMul_State* state, ARMword addr){ - #if 0 - for(int i = 0; i < 128; i++){ - if(state->exclusive_tag_array[i] == 0xffffffff){ - state->exclusive_tag_array[i] = addr; - //printf("In %s, add addr 0x%x\n", __func__, addr); - return; - } - } - printf("In %s ,can not monitor the addr, out of array\n", __FUNCTION__); - #endif - state->exclusive_tag_array[0] = addr; - return; -} - -static void remove_exclusive(ARMul_State* state, ARMword addr){ - #if 0 - int i; - for(i = 0; i < 128; i++){ - if(state->exclusive_tag_array[i] == addr){ - state->exclusive_tag_array[i] = 0xffffffff; - //printf("In %s, remove addr 0x%x\n", __func__, addr); - return; - } - } - #endif - state->exclusive_tag_array[0] = 0xFFFFFFFF; -} - -/* This function encodes table 8-2 Interpreting AP bits, - returning non-zero if access is allowed. */ -static int -check_perms (ARMul_State *state, int ap, int read) -{ - int s, r, user; - - s = state->mmu.control & CONTROL_SYSTEM; - r = state->mmu.control & CONTROL_ROM; - /* chy 2006-02-15 , should consider system mode, don't conside 26bit mode */ -// printf("ap is %x, user is %x, s is %x, read is %x\n", ap, user, s, read); -// printf("mode is %x\n", state->Mode); - user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); - - switch (ap) { - case 0: - return read && ((s && !user) || r); - case 1: - return !user; - case 2: - return read || !user; - case 3: - return 1; - } - return 0; -} - -#if 0 -fault_t -check_access (ARMul_State *state, ARMword virt_addr, tlb_entry_t *tlb, - int read) -{ - int access; - - state->mmu.last_domain = tlb->domain; - access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; - if ((access == 0) || (access == 2)) { - /* It's unclear from the documentation whether this - should always raise a section domain fault, or if - it should be a page domain fault in the case of an - L1 that describes a page table. In the ARM710T - datasheets, "Figure 8-9: Sequence for checking faults" - seems to indicate the former, while "Table 8-4: Priority - encoding of fault status" gives a value for FS[3210] in - the event of a domain fault for a page. Hmm. */ - return SECTION_DOMAIN_FAULT; - } - if (access == 1) { - /* client access - check perms */ - int subpage, ap; -#if 0 - switch (tlb->mapping) { - /*ks 2004-05-09 - * only for XScale - * Extend Small Page(ESP) Format - * 31-12 bits the base addr of ESP - * 11-10 bits SBZ - * 9-6 bits TEX - * 5-4 bits AP - * 3 bit C - * 2 bit B - * 1-0 bits 11 - * */ - case TLB_ESMALLPAGE: /* xj */ - subpage = 0; - /* printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); */ - break; - - case TLB_TINYPAGE: - subpage = 0; - /* printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); */ - break; - - case TLB_SMALLPAGE: - subpage = (virt_addr >> 10) & 3; - break; - case TLB_LARGEPAGE: - subpage = (virt_addr >> 14) & 3; - break; - case TLB_SECTION: - subpage = 3; - break; - default: - assert (0); - subpage = 0; /* cleans a warning */ - } - ap = (tlb->perms >> (subpage * 2 + 4)) & 3; - if (!check_perms (state, ap, read)) { - if (tlb->mapping == TLB_SECTION) { - return SECTION_PERMISSION_FAULT; - } else { - return SUBPAGE_PERMISSION_FAULT; - } - } -#endif - } else { /* access == 3 */ - /* manager access - don't check perms */ - } - return NO_FAULT; -} -#endif - -#if 0 -fault_t -mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr) -#endif - -/* ap: AP bits value. - * sop: section or page description 0:section 1:page - */ -fault_t -mmu_translate (ARMul_State *state, ARMword virt_addr, ARMword *phys_addr, int *ap, int *sop) -{ - { - /* walk the translation tables */ - ARMword l1addr, l1desc; - if (state->mmu.translation_table_ctrl && virt_addr << state->mmu.translation_table_ctrl >> (32 - state->mmu.translation_table_ctrl - 1)) { - l1addr = state->mmu.translation_table_base1; - l1addr = (((l1addr >> 14) << 14) | (virt_addr >> 18)) & ~3; - } else { - l1addr = state->mmu.translation_table_base0; - l1addr = (((l1addr >> (14 - state->mmu.translation_table_ctrl)) << (14 - state->mmu.translation_table_ctrl)) | (virt_addr << state->mmu.translation_table_ctrl) >> (18 + state->mmu.translation_table_ctrl)) & ~3; - } - - /* l1desc = mem_read_word (state, l1addr); */ - if (state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, l1addr, &l1desc, 4); - else - l1desc = Memory::Read32(l1addr); //mem_read_raw(32, l1addr, &l1desc); - - #if 0 - if (virt_addr == 0xc000d2bc) { - printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); - printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); - printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); - printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); - // exit(-1); - } - #endif - switch (l1desc & 3) { - case 0: - case 3: - /* - * according to Figure 3-9 Sequence for checking faults in arm manual, - * section translation fault should be returned here. - */ - { - return SECTION_TRANSLATION_FAULT; - } - case 1: - /* coarse page table */ - { - ARMword l2addr, l2desc; - - - l2addr = l1desc & 0xFFFFFC00; - l2addr = (l2addr | - ((virt_addr & 0x000FF000) >> 10)) & - ~3; - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, l2addr, &l2desc, 4); - else - l2desc = Memory::Read32(l2addr); //mem_read_raw(32, l2addr, &l2desc); - - /* chy 2003-09-02 for xscale */ - *ap = (l2desc >> 4) & 0x3; - *sop = 1; /* page */ - - switch (l2desc & 3) { - case 0: - return PAGE_TRANSLATION_FAULT; - break; - case 1: - *phys_addr = (l2desc & 0xFFFF0000) | (virt_addr & 0x0000FFFF); - break; - case 2: - case 3: - *phys_addr = (l2desc & 0xFFFFF000) | (virt_addr & 0x00000FFF); - break; - - } - } - break; - case 2: - /* section */ - - *ap = (l1desc >> 10) & 3; - *sop = 0; /* section */ - #if 0 - if (virt_addr == 0xc000d2bc) { - printf("mmu_control is %x\n", state->mmu.translation_table_ctrl); - printf("mmu_table_0 is %x\n", state->mmu.translation_table_base0); - printf("mmu_table_1 is %x\n", state->mmu.translation_table_base1); - printf("l1addr is %x l1desc is %x\n", l1addr, l1desc); -// printf("l2addr is %x l2desc is %x\n", l2addr, l2desc); - printf("ap is %x, sop is %x\n", *ap, *sop); - printf("mode is %d\n", state->Mode); -// exit(-1); - } - #endif - - if (l1desc & 0x30000) - *phys_addr = (l1desc & 0xFF000000) | (virt_addr & 0x00FFFFFF); - else - *phys_addr = (l1desc & 0xFFF00000) | (virt_addr & 0x000FFFFF); - break; - } - } - return NO_FAULT; -} - - -static fault_t arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, - ARMword data, ARMword datatype); -static fault_t arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, - ARMword *data, ARMword datatype); - -int -arm1176jzf_s_mmu_init (ARMul_State *state) -{ - state->mmu.control = 0x50078; - state->mmu.translation_table_base = 0xDEADC0DE; - state->mmu.domain_access_control = 0xDEADC0DE; - state->mmu.fault_status = 0; - state->mmu.fault_address = 0; - state->mmu.process_id = 0; - state->mmu.context_id = 0; - state->mmu.thread_uro_id = 0; - //invalidate_all_tlb(state); - - return No_exp; -} - -void -arm1176jzf_s_mmu_exit (ARMul_State *state) -{ -} - - -static fault_t -arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr) -{ - fault_t fault; - int c; /* cache bit */ - ARMword pa; /* physical addr */ - ARMword perm; /* physical addr access permissions */ - int ap, sop; - - static int debug_count = 0; /* used for debug */ - - //DEBUG_LOG(ARM11, "va = %x\n", va); - - va = mmu_pid_va_map (va); - if (MMU_Enabled) { -// printf("MMU enabled.\n"); -// sleep(1); - /* align check */ - if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } else - va &= ~(WORD_SIZE - 1); - - /* translate tlb */ - fault = mmu_translate (state, va, &pa, &ap, &sop); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - printf("va=0x%x, icounter=%lld, fault=%d\n", va, state->NumInstrs, fault); - return fault; - } - - - /* no tlb, only check permission */ - if (!check_perms(state, ap, 1)) { - if (sop == 0) { - return SECTION_PERMISSION_FAULT; - } else { - return SUBPAGE_PERMISSION_FAULT; - } - } - -#if 0 - /*check access */ - fault = check_access (state, va, tlb, 1); - if (fault) { - DEBUG_LOG(ARM11, "check_fault\n"); - return fault; - } -#endif - } - - /*if MMU disabled or C flag is set alloc cache */ - if (MMU_Disabled) { -// printf("MMU disabled.\n"); -// sleep(1); - pa = va; - } - if(state->space.conf_obj == NULL) - state->space.read(state->space.conf_obj, pa, instr, 4); - else - *instr = Memory::Read32(pa); //mem_read_raw(32, pa, instr); - - return NO_FAULT; -} - -static fault_t -arm1176jzf_s_mmu_read_byte (ARMul_State *state, ARMword virt_addr, ARMword *data) -{ - /* ARMword temp,offset; */ - fault_t fault; - fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); - return fault; -} - -static fault_t -arm1176jzf_s_mmu_read_halfword (ARMul_State *state, ARMword virt_addr, - ARMword *data) -{ - /* ARMword temp,offset; */ - fault_t fault; - fault = arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); - return fault; -} - -static fault_t -arm1176jzf_s_mmu_read_word (ARMul_State *state, ARMword virt_addr, ARMword *data) -{ - return arm1176jzf_s_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); -} - -static fault_t -arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data, - ARMword datatype) -{ - fault_t fault; - ARMword pa, real_va, temp, offset; - ARMword perm; /* physical addr access permissions */ - int ap, sop; - - //DEBUG_LOG(ARM11, "va = %x\n", va); - - va = mmu_pid_va_map (va); - real_va = va; - /* if MMU disabled, memory_read */ - if (MMU_Disabled) { -// printf("MMU disabled cpu_id:%x addr:%x.\n", state->mmu.process_id, va); -// sleep(1); - - /* *data = mem_read_word(state, va); */ - if (datatype == ARM_BYTE_TYPE) - /* *data = mem_read_byte (state, va); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, va, data, 1); - else - *data = Memory::Read8(va); //mem_read_raw(8, va, data); - else if (datatype == ARM_HALFWORD_TYPE) - /* *data = mem_read_halfword (state, va); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, va, data, 2); - else - *data = Memory::Read16(va); //mem_read_raw(16, va, data); - else if (datatype == ARM_WORD_TYPE) - /* *data = mem_read_word (state, va); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, va, data, 4); - else - *data = Memory::Read32(va); //mem_read_raw(32, va, data); - else { - ERROR_LOG(ARM11, "SKYEYE:1 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); - } - - return NO_FAULT; - } -// printf("MMU enabled.\n"); -// sleep(1); - - /* align check */ - if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || - ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } - - /* va &= ~(WORD_SIZE - 1); */ - #if 0 - uint32_t page_base; - page_base = get_phys_page(state, va); - if((page_base & 0xFFF) == 0){ - pa = (page_base << 12) | (va & 0xFFF); - goto skip_translation; - } - #endif - /*translate va to tlb */ -#if 0 - fault = mmu_translate (state, va, ARM920T_D_TLB (), &tlb); -#endif - fault = mmu_translate (state, va, &pa, &ap, &sop); -#if 0 - if(va ==0xbebb1774 || state->Reg[15] == 0x400ff594){ - //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); - printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); - int i; - for(i = 0; i < 16; i++) - printf("Reg[%d]=0x%x\t", i, state->Reg[i]); - printf("\n"); - } -#endif - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - //printf("mmu read fault at %x\n", va); - //printf("fault is %d\n", fault); - return fault; - } -// printf("va is %x pa is %x\n", va, pa); - - /* no tlb, only check permission */ - if (!check_perms(state, ap, 1)) { - if (sop == 0) { - return SECTION_PERMISSION_FAULT; - } else { - return SUBPAGE_PERMISSION_FAULT; - } - } -#if 0 - /*check access permission */ - fault = check_access (state, va, tlb, 1); - if (fault) - return fault; -#endif - - //insert_tlb(state, va, pa); -skip_translation: - /* *data = mem_read_word(state, pa); */ - if (datatype == ARM_BYTE_TYPE) { - /* *data = mem_read_byte (state, pa | (real_va & 3)); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 1); - else - *data = Memory::Read8(pa | (real_va & 3)); //mem_read_raw(8, pa | (real_va & 3), data); - /* mem_read_raw(32, pa | (real_va & 3), data); */ - } else if (datatype == ARM_HALFWORD_TYPE) { - /* *data = mem_read_halfword (state, pa | (real_va & 2)); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, pa | (real_va & 3), data, 2); - else - *data = Memory::Read16(pa | (real_va & 3)); //mem_read_raw(16, pa | (real_va & 3), data); - /* mem_read_raw(32, pa | (real_va & 2), data); */ - } else if (datatype == ARM_WORD_TYPE) - /* *data = mem_read_word (state, pa); */ - if(state->space.conf_obj != NULL) - state->space.read(state->space.conf_obj, pa , data, 4); - else - *data = Memory::Read32(pa); //mem_read_raw(32, pa, data); - else { - ERROR_LOG(ARM11, "SKYEYE:2 arm1176jzf_s_mmu_read error: unknown data type %d\n", datatype); - } - if(0 && (va == 0x2869c)){ - printf("In %s, pa is %x va=0x%x, value is %x pc %x, instr=0x%x\n", __FUNCTION__, pa, va, *data, state->Reg[15], state->CurrInstr); - } - - /* ldrex or ldrexb */ - if(((state->CurrInstr & 0x0FF000F0) == 0x01900090) || - ((state->CurrInstr & 0x0FF000F0) == 0x01d00090)){ - int rn = (state->CurrInstr & 0xF0000) >> 16; - if(state->Reg[rn] == va){ - add_exclusive_addr(state, pa | (real_va & 3)); - state->exclusive_access_state = 1; - } - } -#if 0 - if (state->pc == 0xc011a868) { - printf("pa is %x value is %x size is %x\n", pa, data, datatype); - printf("icounter is %lld\n", state->NumInstrs); -// exit(-1); - } -#endif - - return NO_FAULT; -} - - -static fault_t -arm1176jzf_s_mmu_write_byte (ARMul_State *state, ARMword virt_addr, ARMword data) -{ - return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); -} - -static fault_t -arm1176jzf_s_mmu_write_halfword (ARMul_State *state, ARMword virt_addr, - ARMword data) -{ - return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); -} - -static fault_t -arm1176jzf_s_mmu_write_word (ARMul_State *state, ARMword virt_addr, ARMword data) -{ - return arm1176jzf_s_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); -} - - - -static fault_t -arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data, - ARMword datatype) -{ - int b; - ARMword pa, real_va; - ARMword perm; /* physical addr access permissions */ - fault_t fault; - int ap, sop; - -#if 0 - /8 for sky_printk debugger.*/ - if (va == 0xffffffff) { - putchar((char)data); - return 0; - } - if (va == 0xBfffffff) { - putchar((char)data); - return 0; - } -#endif - - //DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); - va = mmu_pid_va_map (va); - real_va = va; - - if (MMU_Disabled) { - /* mem_write_word(state, va, data); */ - if (datatype == ARM_BYTE_TYPE) - /* mem_write_byte (state, va, data); */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, va, &data, 1); - else - Memory::Write8(va, data); - else if (datatype == ARM_HALFWORD_TYPE) - /* mem_write_halfword (state, va, data); */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, va, &data, 2); - else - Memory::Write16(va, data); - else if (datatype == ARM_WORD_TYPE) - /* mem_write_word (state, va, data); */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, va, &data, 4); - else - Memory::Write32(va, data); - else { - ERROR_LOG (ARM11, "SKYEYE:1 arm1176jzf_s_mmu_write error: unknown data type %d\n", datatype); - } - goto finished_write; - //return 0; - } - /*align check */ - /* if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ */ - if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || - ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } - va &= ~(WORD_SIZE - 1); - #if 0 - uint32_t page_base; - page_base = get_phys_page(state, va); - if((page_base & 0xFFF) == 0){ - pa = (page_base << 12) | (va & 0xFFF); - goto skip_translation; - } - #endif - /*tlb translate */ - fault = mmu_translate (state, va, &pa, &ap, &sop); -#if 0 - if(va ==0xbebb1774 || state->Reg[15] == 0x40102334){ - //printf("In %s, current=0x%x. mode is %x, pc=0x%x\n", __FUNCTION__, state->CurrInstr, state->Mode, state->Reg[15]); - printf("In %s, ap is %d, sop is %d, va=0x%x, pa=0x%x, fault=%d, data=0x%x\n", __FUNCTION__, ap, sop, va, pa, fault, data); - int i; - for(i = 0; i < 16; i++) - printf("Reg[%d]=0x%x\t", i, state->Reg[i]); - printf("\n"); - } -#endif - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - //printf("mmu write fault at %x\n", va); - return fault; - } -// printf("va is %x pa is %x\n", va, pa); - - /* no tlb, only check permission */ - if (!check_perms(state, ap, 0)) { - if (sop == 0) { - return SECTION_PERMISSION_FAULT; - } else { - return SUBPAGE_PERMISSION_FAULT; - } - } - -#if 0 - /* tlb check access */ - fault = check_access (state, va, tlb, 0); - if (fault) { - DEBUG_LOG(ARM11, "check_access\n"); - return fault; - } -#endif -#if 0 - if (pa <= 0x502860ff && (pa + 1 << datatype) > 0x502860ff) { - printf("pa is %x value is %x size is %x\n", pa, data, datatype); - } -#endif -#if 0 - if (state->pc == 0xc011a878) { - printf("write pa is %x value is %x size is %x\n", pa, data, datatype); - printf("icounter is %lld\n", state->NumInstrs); - exit(-1); - } -#endif - //insert_tlb(state, va, pa); -skip_translation: - /* strex */ - if(((state->CurrInstr & 0x0FF000F0) == 0x01800090) || - ((state->CurrInstr & 0x0FF000F0) == 0x01c00090)){ - /* failed , the address is monitord now. */ - int dest_reg = (state->CurrInstr & 0xF000) >> 12; - if((exclusive_detect(state, pa | (real_va & 3)) == 0) && (state->exclusive_access_state == 1)){ - remove_exclusive(state, pa | (real_va & 3)); - state->Reg[dest_reg] = 0; - state->exclusive_access_state = 0; - } - else{ - state->Reg[dest_reg] = 1; - //printf("In %s, try to strex a monitored address 0x%x\n", __FUNCTION__, pa); - return NO_FAULT; - } - } - - if (datatype == ARM_BYTE_TYPE) { - /* mem_write_byte (state, - (pa | (real_va & 3)), - data); - */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 1); - else - Memory::Write8((pa | (real_va & 3)), data); - - } else if (datatype == ARM_HALFWORD_TYPE) - /* mem_write_halfword (state, - (pa | - (real_va & 2)), - data); - */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, (pa | (real_va & 3)), &data, 2); - else - Memory::Write16((pa | (real_va & 3)), data); - else if (datatype == ARM_WORD_TYPE) - /* mem_write_word (state, pa, data); */ - if(state->space.conf_obj != NULL) - state->space.write(state->space.conf_obj, pa, &data, 4); - else - Memory::Write32(pa, data); -#if 0 - if (state->NumInstrs > 236403) { - printf("write memory\n"); - printf("pa is %x value is %x size is %x\n", pa, data, datatype); - printf("icounter is %lld\n", state->NumInstrs); - } -#endif -finished_write: -#if DIFF_WRITE - if(state->icounter > state->debug_icounter){ - if(state->CurrWrite >= 17 ){ - printf("Wrong write array, 0x%x", state->CurrWrite); - exit(-1); - } - uint32 record_data = data; - if(datatype == ARM_BYTE_TYPE) - record_data &= 0xFF; - if(datatype == ARM_HALFWORD_TYPE) - record_data &= 0xFFFF; - - state->WriteAddr[state->CurrWrite] = pa | (real_va & 3); - state->WriteData[state->CurrWrite] = record_data; - state->WritePc[state->CurrWrite] = state->Reg[15]; - state->CurrWrite++; - //printf("In %s, pc=0x%x, addr=0x%x, data=0x%x, CFlag=%d\n", __FUNCTION__, state->Reg[15], pa | (real_va & 3), record_data, state->CFlag); - } -#endif - - return NO_FAULT; -} - -ARMword -arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value) -{ - int creg = BITS (16, 19) & 0xf; - int OPC_1 = BITS (21, 23) & 0x7; - int OPC_2 = BITS (5, 7) & 0x7; - ARMword data; - - switch (creg) { - case MMU_ID: - if (OPC_2 == 0) { - data = state->cpu->cpu_val; - } else if (OPC_2 == 1) { - /* Cache type: - * 000 0110 1 000 101 110 0 10 000 101 110 0 10 - * */ - data = 0x0D172172; - } - break; - case MMU_CONTROL: - /* - * 6:3 read as 1 - * 10 read as 0 - * 18,16 read as 1 - * */ - data = (state->mmu.control | 0x50078) & 0xFFFFFBFF; - break; - case MMU_TRANSLATION_TABLE_BASE: -#if 0 - data = state->mmu.translation_table_base; -#endif - switch (OPC_2) { - case 0: - data = state->mmu.translation_table_base0; - break; - case 1: - data = state->mmu.translation_table_base1; - break; - case 2: - data = state->mmu.translation_table_ctrl; - break; - default: - printf ("mmu_mrc read UNKNOWN - p15 c2 opcode2 %d\n", OPC_2); - break; - } - break; - case MMU_DOMAIN_ACCESS_CONTROL: - data = state->mmu.domain_access_control; - break; - case MMU_FAULT_STATUS: - /* OPC_2 = 0: data FSR value - * */ - if (OPC_2 == 0) - data = state->mmu.fault_status; - if (OPC_2 == 1) - data = state->mmu.fault_statusi; - break; - case MMU_FAULT_ADDRESS: - data = state->mmu.fault_address; - break; - case MMU_PID: - //data = state->mmu.process_id; - if(OPC_2 == 0) - data = state->mmu.process_id; - else if(OPC_2 == 1) - data = state->mmu.context_id; - else if(OPC_2 == 3){ - data = state->mmu.thread_uro_id; - } - else{ - printf ("mmu_mcr read UNKNOWN - reg %d\n", creg); - } - //printf("SKYEYE In %s, read pid 0x%x, OPC_2 %d, instr=0x%x\n", __FUNCTION__, data, OPC_2, instr); - //exit(-1); - break; - default: - printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); - data = 0; - break; - } -/* printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); */ - *value = data; - return data; -} - - -static ARMword -arm1176jzf_s_mmu_mcr (ARMul_State *state, ARMword instr, ARMword value) -{ - int creg = BITS (16, 19) & 0xf; - int CRm = BITS (0, 3) & 0xf; - int OPC_1 = BITS (21, 23) & 0x7; - int OPC_2 = BITS (5, 7) & 0x7; - if (!strncmp (state->cpu->cpu_arch_name, "armv6", 5)) { - switch (creg) { - case MMU_CONTROL: - /* - * 6:3 read as 1 - * 10 read as 0 - * 18,16 read as 1 - * */ - if(OPC_2 == 0) - state->mmu.control = (value | 0x50078) & 0xFFFFFBFF; - else if(OPC_2 == 1) - state->mmu.auxiliary_control = value; - else if(OPC_2 == 2) - state->mmu.coprocessor_access_control = value; - else - fprintf(stderr, "In %s, wrong OPC_2 %d\n", __FUNCTION__, OPC_2); - break; - case MMU_TRANSLATION_TABLE_BASE: - switch (OPC_2) { - /* int i; */ - case 0: -#if 0 - /* TTBR0 */ - if (state->mmu.translation_table_ctrl & 0x7) { - for (i = 0; i <= state->mmu.translation_table_ctrl; i++) - state->mmu.translation_table_base0 &= ~(1 << (5 + i)); - } -#endif - state->mmu.translation_table_base0 = (value); - break; - case 1: -#if 0 - /* TTBR1 */ - if (state->mmu.translation_table_ctrl & 0x7) { - for (i = 0; i <= state->mmu.translation_table_ctrl; i++) - state->mmu.translation_table_base1 &= 1 << (5 + i); - } -#endif - state->mmu.translation_table_base1 = (value); - break; - case 2: - /* TTBC */ - state->mmu.translation_table_ctrl = value & 0x7; - break; - default: - printf ("mmu_mcr wrote UNKNOWN - cp15 c2 opcode2 %d\n", OPC_2); - break; - } - //printf("SKYEYE In %s, write TLB_BASE 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); - //invalidate_all_tlb(state); - break; - case MMU_DOMAIN_ACCESS_CONTROL: - /* printf("mmu_mcr wrote DACR "); */ - state->mmu.domain_access_control = value; - break; - - case MMU_FAULT_STATUS: - if (OPC_2 == 0) - state->mmu.fault_status = value & 0xFF; - if (OPC_2 == 1) { - printf("set fault status instr\n"); - } - break; - case MMU_FAULT_ADDRESS: - state->mmu.fault_address = value; - break; - - case MMU_CACHE_OPS: - break; - case MMU_TLB_OPS: - { - switch(CRm){ - case 5: /* ITLB */ - { - switch(OPC_2){ - case 0: /* invalidate all */ - //invalidate_all_tlb(state); - break; - case 1: /* invalidate by MVA */ - //invalidate_by_mva(state, value); - break; - case 2: /* invalidate by asid */ - //invalidate_by_asid(state, value); - break; - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - break; - } - case 6: /* DTLB */ - { - switch(OPC_2){ - case 0: /* invalidate all */ - //invalidate_all_tlb(state); - break; - case 1: /* invalidate by MVA */ - //invalidate_by_mva(state, value); - break; - case 2: /* invalidate by asid */ - //invalidate_by_asid(state, value); - break; - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - break; - } - case 7: /* Unified TLB */ - { - switch(OPC_2){ - case 0: /* invalidate all */ - //invalidate_all_tlb(state); - break; - case 1: /* invalidate by MVA */ - //invalidate_by_mva(state, value); - break; - case 2: /* invalidate by asid */ - //invalidate_by_asid(state, value); - break; - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - break; - } - - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d, CRm=%d\n", creg, CRm); - break; - } - //printf("SKYEYE In %s, write TLB 0x%x OPC_1=%d, OPC_2=%d , CRm=%d instr=0x%x\n", __FUNCTION__, value, OPC_1, OPC_2, CRm, instr); - } - break; - case MMU_CACHE_LOCKDOWN: - /* - * FIXME: cache lock down*/ - break; - case MMU_TLB_LOCKDOWN: - printf("SKYEYE In %s, write TLB_LOCKDOWN 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); - /* FIXME:tlb lock down */ - break; - case MMU_PID: - //printf("SKYEYE In %s, write pid 0x%x OPC_2=%d instr=0x%x\n", __FUNCTION__, value, OPC_2, instr); - //state->mmu.process_id = value; - /*0:24 should be zero. */ - //state->mmu.process_id = value & 0xfe000000; - if(OPC_2 == 0) - state->mmu.process_id = value; - else if(OPC_2 == 1) - state->mmu.context_id = value; - else if(OPC_2 == 3){ - state->mmu.thread_uro_id = value; - } - else{ - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - } - break; - - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - } - - return No_exp; -} - -///* teawater add for arm2x86 2005.06.19------------------------------------------- */ -//static int -//arm1176jzf_s_mmu_v2p_dbct (ARMul_State *state, ARMword virt_addr, -// ARMword *phys_addr) -//{ -// fault_t fault; -// int ap, sop; -// -// ARMword perm; /* physical addr access permissions */ -// virt_addr = mmu_pid_va_map (virt_addr); -// if (MMU_Enabled) { -// -// /*align check */ -// if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { -// DEBUG_LOG(ARM11, "align\n"); -// return ALIGNMENT_FAULT; -// } else -// virt_addr &= ~(WORD_SIZE - 1); -// -// /*translate tlb */ -// fault = mmu_translate (state, virt_addr, phys_addr, &ap, &sop); -// if (fault) { -// DEBUG_LOG(ARM11, "translate\n"); -// return fault; -// } -// -// /* permission check */ -// if (!check_perms(state, ap, 1)) { -// if (sop == 0) { -// return SECTION_PERMISSION_FAULT; -// } else { -// return SUBPAGE_PERMISSION_FAULT; -// } -// } -//#if 0 -// /*check access */ -// fault = check_access (state, virt_addr, tlb, 1); -// if (fault) { -// DEBUG_LOG(ARM11, "check_fault\n"); -// return fault; -// } -//#endif -// } -// -// if (MMU_Disabled) { -// *phys_addr = virt_addr; -// } -// -// return 0; -//} - -/* AJ2D-------------------------------------------------------------------------- */ - -/*arm1176jzf-s mmu_ops_t*/ -mmu_ops_t arm1176jzf_s_mmu_ops = { - arm1176jzf_s_mmu_init, - arm1176jzf_s_mmu_exit, - arm1176jzf_s_mmu_read_byte, - arm1176jzf_s_mmu_write_byte, - arm1176jzf_s_mmu_read_halfword, - arm1176jzf_s_mmu_write_halfword, - arm1176jzf_s_mmu_read_word, - arm1176jzf_s_mmu_write_word, - arm1176jzf_s_mmu_load_instr, - arm1176jzf_s_mmu_mcr, - arm1176jzf_s_mmu_mrc -/* teawater add for arm2x86 2005.06.19------------------------------------------- */ -/* arm1176jzf_s_mmu_v2p_dbct, */ -/* AJ2D-------------------------------------------------------------------------- */ -}; diff --git a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h b/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h deleted file mode 100644 index 299c6b46b..000000000 --- a/src/core/arm/interpreter/mmu/arm1176jzf_s_mmu.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - arm1176JZF-S_mmu.h - ARM1176JZF-S Memory Management Unit emulation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _ARM1176JZF_S_MMU_H_ -#define _ARM1176JZF_S_MMU_H_ - -#if 0 -typedef struct arm1176jzf-s_mmu_s -{ - tlb_t i_tlb; - cache_t i_cache; - - tlb_t d_tlb; - cache_t d_cache; - wb_t wb_t; -} arm1176jzf-s_mmu_t; -#endif -extern mmu_ops_t arm1176jzf_s_mmu_ops; - -ARMword -arm1176jzf_s_mmu_mrc (ARMul_State *state, ARMword instr, ARMword *value); -#endif /*_ARM1176JZF_S_MMU_H_*/ diff --git a/src/core/arm/interpreter/mmu/cache.cpp b/src/core/arm/interpreter/mmu/cache.cpp deleted file mode 100644 index f3c4e0531..000000000 --- a/src/core/arm/interpreter/mmu/cache.cpp +++ /dev/null @@ -1,370 +0,0 @@ -#include "core/arm/interpreter/armdefs.h" - -/* mmu cache init - * - * @cache_t :cache_t to init - * @width :cache line width in byte - * @way :way of each cache set - * @set :cache set num - * - * $ -1: error - * 0: sucess - */ -int -mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode) -{ - int i, j; - cache_set_t *sets; - cache_line_t *lines; - - /*alloc cache set */ - sets = NULL; - lines = NULL; - //fprintf(stderr, "mmu_cache_init: mallloc beg size %d,sets 0x%x\n", sizeof(cache_set_t) * set,sets); - //exit(-1); - sets = (cache_set_t *) malloc (sizeof (cache_set_t) * set); - if (sets == NULL) { - ERROR_LOG(ARM11, "set malloc size %d\n", sizeof (cache_set_t) * set); - goto sets_error; - } - //fprintf(stderr, "mmu_cache_init: mallloc end sets 0x%x\n", sets); - cache_t->sets = sets; - - /*init cache set */ - for (i = 0; i < set; i++) { - /*alloc cache line */ - lines = (cache_line_t *) malloc (sizeof (cache_line_t) * way); - if (lines == NULL) { - ERROR_LOG(ARM11, "line malloc size %d\n", - sizeof (cache_line_t) * way); - goto lines_error; - } - /*init cache line */ - for (j = 0; j < way; j++) { - lines[j].tag = 0; //invalid - lines[j].data = (ARMword *) malloc (width); - if (lines[j].data == NULL) { - ERROR_LOG(ARM11, "data alloc size %d\n", width); - goto data_error; - } - } - - sets[i].lines = lines; - sets[i].cycle = 0; - - } - cache_t->width = width; - cache_t->set = set; - cache_t->way = way; - cache_t->w_mode = w_mode; - return 0; - - data_error: - /*free data */ - while (j-- > 0) - free (lines[j].data); - /*free data error line */ - free (lines); - lines_error: - /*free lines already alloced */ - while (i-- > 0) { - for (j = 0; j < way; j++) - free (sets[i].lines[j].data); - free (sets[i].lines); - } - /*free sets */ - free (sets); - sets_error: - return -1; -}; - -/* free a cache_t's inner data, the ptr self is not freed, - * when needed do like below: - * mmu_cache_exit(cache); - * free(cache_t); - * - * @cache_t : the cache_t to free - */ - -void -mmu_cache_exit (cache_s * cache_t) -{ - int i, j; - cache_set_t *sets, *set; - cache_line_t *lines, *line; - - /*free all set */ - sets = cache_t->sets; - for (set = sets, i = 0; i < cache_t->set; i++, set++) { - /*free all line */ - lines = set->lines; - for (line = lines, j = 0; j < cache_t->way; j++, line++) - free (line->data); - free (lines); - } - free (sets); -} - -/* mmu cache search - * - * @state :ARMul_State - * @cache_t :cache_t to search - * @va :virtual address - * - * $ NULL: no cache match - * cache :cache matched - */ -cache_line_t * -mmu_cache_search (ARMul_State * state, cache_s * cache_t, ARMword va) -{ - int i; - int set = va_cache_set (va, cache_t); - ARMword tag = va_cache_align (va, cache_t); - cache_line_t *cache; - - cache_set_t *cache_set = cache_t->sets + set; - for (i = 0, cache = cache_set->lines; i < cache_t->way; i++, cache++) { - if ((cache->tag & TAG_VALID_FLAG) - && (tag == va_cache_align (cache->tag, cache_t))) - return cache; - } - return NULL; -} - -/* mmu cache search by set/index - * - * @state :ARMul_State - * @cache_t :cache_t to search - * @index :set/index value. - * - * $ NULL: no cache match - * cache :cache matched - */ -cache_line_t * -mmu_cache_search_by_index (ARMul_State * state, cache_s * cache_t, - ARMword index) -{ - int way = cache_t->way; - int set_v = index_cache_set (index, cache_t); - int i = 0, index_v = 0; - cache_set_t *set; - - while ((way >>= 1) >= 1) - i++; - index_v = index >> (32 - i); - set = cache_t->sets + set_v; - - return set->lines + index_v; -} - - -/* mmu cache alloc - * - * @state :ARMul_State - * @cache_t :cache_t to alloc from - * @va :virtual address that require cache alloc, need not cache aligned - * @pa :physical address of va - * - * $ cache_alloced, always alloc OK - */ -cache_line_t * -mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, ARMword va, - ARMword pa) -{ - cache_line_t *cache; - cache_set_t *set; - int i; - - va = va_cache_align (va, cache_t); - pa = va_cache_align (pa, cache_t); - - set = &cache_t->sets[va_cache_set (va, cache_t)]; - - /*robin-round */ - cache = &set->lines[set->cycle++]; - if (set->cycle == cache_t->way) - set->cycle = 0; - - if (cache_t->w_mode == CACHE_WRITE_BACK) { - ARMword t; - - /*if cache valid, try to write back */ - if (cache->tag & TAG_VALID_FLAG) { - mmu_cache_write_back (state, cache_t, cache); - } - /*read in cache_line */ - t = pa; - for (i = 0; i < (cache_t->width >> WORD_SHT); - i++, t += WORD_SIZE) { - //cache->data[i] = mem_read_word (state, t); - bus_read(32, t, &cache->data[i]); - } - } - /*store tag and pa */ - cache->tag = va | TAG_VALID_FLAG; - cache->pa = pa; - - return cache; -}; - -/* mmu_cache_write_back write cache data to memory - * @state - * @cache_t :cache_t of the cache line - * @cache : cache line - */ -void -mmu_cache_write_back (ARMul_State * state, cache_s * cache_t, - cache_line_t * cache) -{ - ARMword pa = cache->pa; - int nw = cache_t->width >> WORD_SHT; - ARMword *data = cache->data; - int i; - int t0, t1, t2; - - if ((cache->tag & 1) == 0) - return; - - switch (cache-> - tag & ~1 & (TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY)) { - case 0: - return; - case TAG_FIRST_HALF_DIRTY: - nw /= 2; - break; - case TAG_LAST_HALF_DIRTY: - nw /= 2; - pa += nw << WORD_SHT; - data += nw; - break; - case TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY: - break; - } - for (i = 0; i < nw; i++, data++, pa += WORD_SIZE) - //mem_write_word (state, pa, *data); - bus_write(32, pa, *data); - - cache->tag &= ~(TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY); -}; - - -/* mmu_cache_clean: clean a cache of va in cache_t - * - * @state :ARMul_State - * @cache_t :cache_t to clean - * @va :virtaul address - */ -void -mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va) -{ - cache_line_t *cache; - - cache = mmu_cache_search (state, cache_t, va); - if (cache) - mmu_cache_write_back (state, cache_t, cache); -} - -/* mmu_cache_clean_by_index: clean a cache by set/index format value - * - * @state :ARMul_State - * @cache_t :cache_t to clean - * @va :set/index format value - */ -void -mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t, - ARMword index) -{ - cache_line_t *cache; - - cache = mmu_cache_search_by_index (state, cache_t, index); - if (cache) - mmu_cache_write_back (state, cache_t, cache); -} - -/* mmu_cache_invalidate : invalidate a cache of va - * - * @state :ARMul_State - * @cache_t :cache_t to invalid - * @va :virt_addr to invalid - */ -void -mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va) -{ - cache_line_t *cache; - - cache = mmu_cache_search (state, cache_t, va); - if (cache) { - mmu_cache_write_back (state, cache_t, cache); - cache->tag = 0; - } -} - -/* mmu_cache_invalidate_by_index : invalidate a cache by index format - * - * @state :ARMul_State - * @cache_t :cache_t to invalid - * @index :set/index data - */ -void -mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t, - ARMword index) -{ - cache_line_t *cache; - - cache = mmu_cache_search_by_index (state, cache_t, index); - if (cache) { - mmu_cache_write_back (state, cache_t, cache); - cache->tag = 0; - } -} - -/* mmu_cache_invalidate_all - * - * @state: - * @cache_t - * */ -void -mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t) -{ - int i, j; - cache_set_t *set; - cache_line_t *cache; - - set = cache_t->sets; - for (i = 0; i < cache_t->set; i++, set++) { - cache = set->lines; - for (j = 0; j < cache_t->way; j++, cache++) { - mmu_cache_write_back (state, cache_t, cache); - cache->tag = 0; - } - } -}; - -void -mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa) -{ - ARMword set, way; - cache_line_t *cache; - pa = (pa / cache_t->width); - way = pa & (cache_t->way - 1); - set = (pa / cache_t->way) & (cache_t->set - 1); - cache = &cache_t->sets[set].lines[way]; - - mmu_cache_write_back (state, cache_t, cache); - cache->tag = 0; -} - -cache_line_t* mmu_cache_dirty_cache(ARMul_State *state,cache_s *cache){ - int i; - int j; - cache_line_t *cache_line = NULL; - cache_set_t *cache_set = cache->sets; - int sets = cache->set; - for (i = 0; i < sets; i++){ - for(j = 0,cache_line = &cache_set[i].lines[0]; j < cache->way; j++,cache_line++){ - if((cache_line->tag & TAG_FIRST_HALF_DIRTY) || (cache_line->tag & TAG_LAST_HALF_DIRTY)) - return cache_line; - } - } - return NULL; -} diff --git a/src/core/arm/interpreter/mmu/cache.h b/src/core/arm/interpreter/mmu/cache.h deleted file mode 100644 index d308d9b87..000000000 --- a/src/core/arm/interpreter/mmu/cache.h +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef _MMU_CACHE_H_ -#define _MMU_CACHE_H_ - -typedef struct cache_line_t -{ - ARMword tag; /* cache line align address | - bit2: last half dirty - bit1: first half dirty - bit0: cache valid flag - */ - ARMword pa; /*physical address */ - ARMword *data; /*array of cached data */ -} cache_line_t; -#define TAG_VALID_FLAG 0x00000001 -#define TAG_FIRST_HALF_DIRTY 0x00000002 -#define TAG_LAST_HALF_DIRTY 0x00000004 - -/*cache set association*/ -typedef struct cache_set_s -{ - cache_line_t *lines; - int cycle; -} cache_set_t; - -enum -{ - CACHE_WRITE_BACK, - CACHE_WRITE_THROUGH, -}; - -typedef struct cache_s -{ - int width; /*bytes in a line */ - int way; /*way of set asscociate */ - int set; /*num of set */ - int w_mode; /*write back or write through */ - //int a_mode; /*alloc mode: random or round-bin*/ - cache_set_t *sets; - /**/} cache_s; - -typedef struct cache_desc_s -{ - int width; - int way; - int set; - int w_mode; -// int a_mode; -} cache_desc_t; - - -/*virtual address to cache set index*/ -#define va_cache_set(va, cache_t) \ - (((va) / (cache_t)->width) & ((cache_t)->set - 1)) -/*virtual address to cahce line aligned*/ -#define va_cache_align(va, cache_t) \ - ((va) & ~((cache_t)->width - 1)) -/*virtaul address to cache line word index*/ -#define va_cache_index(va, cache_t) \ - (((va) & ((cache_t)->width - 1)) >> WORD_SHT) - -/*see Page 558 in arm manual*/ -/*set/index format value to cache set value*/ -#define index_cache_set(index, cache_t) \ - (((index) / (cache_t)->width) & ((cache_t)->set - 1)) - -/*************************cache********************/ -/* mmu cache init - * - * @cache_t :cache_t to init - * @width :cache line width in byte - * @way :way of each cache set - * @set :cache set num - * @w_mode :cache w_mode - * - * $ -1: error - * 0: sucess - */ -int -mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode); - -/* free a cache_t's inner data, the ptr self is not freed, - * when needed do like below: - * mmu_cache_exit(cache); - * free(cache_t); - * - * @cache_t : the cache_t to free - */ -void mmu_cache_exit (cache_s * cache_t); - -/* mmu cache search - * - * @state :ARMul_State - * @cache_t :cache_t to search - * @va :virtual address - * - * $ NULL: no cache match - * cache :cache matched - * */ -cache_line_t *mmu_cache_search (ARMul_State * state, cache_s * cache_t, - ARMword va); - -/* mmu cache search by set/index - * - * @state :ARMul_State - * @cache_t :cache_t to search - * @index :set/index value. - * - * $ NULL: no cache match - * cache :cache matched - * */ - -cache_line_t *mmu_cache_search_by_index (ARMul_State * state, - cache_s * cache_t, ARMword index); - -/* mmu cache alloc - * - * @state :ARMul_State - * @cache_t :cache_t to alloc from - * @va :virtual address that require cache alloc, need not cache aligned - * @pa :physical address of va - * - * $ cache_alloced, always alloc OK - */ -cache_line_t *mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, - ARMword va, ARMword pa); - -/* mmu_cache_write_back write cache data to memory - * - * @state: - * @cache_t :cache_t of the cache line - * @cache : cache line - */ -void -mmu_cache_write_back (ARMul_State * state, cache_s * cache_t, - cache_line_t * cache); - -/* mmu_cache_clean: clean a cache of va in cache_t - * - * @state :ARMul_State - * @cache_t :cache_t to clean - * @va :virtaul address - */ -void mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va); -void -mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t, - ARMword index); - -/* mmu_cache_invalidate : invalidate a cache of va - * - * @state :ARMul_State - * @cache_t :cache_t to invalid - * @va :virt_addr to invalid - */ -void -mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va); - -void -mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t, - ARMword index); - -void mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t); - -void -mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa); - -cache_line_t* mmu_cache_dirty_cache(ARMul_State * state, cache_s * cache_t); - -#endif /*_MMU_CACHE_H_*/ diff --git a/src/core/arm/interpreter/mmu/maverick.cpp b/src/core/arm/interpreter/mmu/maverick.cpp deleted file mode 100644 index adcc2efb5..000000000 --- a/src/core/arm/interpreter/mmu/maverick.cpp +++ /dev/null @@ -1,1206 +0,0 @@ -/* maverick.c -- Cirrus/DSP co-processor interface. - Copyright (C) 2003 Free Software Foundation, Inc. - Contributed by Aldy Hernandez (aldyh@redhat.com). - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include <assert.h> - -#include "core/arm/interpreter/armdefs.h" -#include "core/arm/interpreter/armemu.h" - - -/*#define CIRRUS_DEBUG 1 */ -#if CIRRUS_DEBUG -# define printfdbg printf -#else -# define printfdbg printf_nothing -#endif - -#define POS64(i) ( (~(i)) >> 63 ) -#define NEG64(i) ( (i) >> 63 ) - -/* Define Co-Processor instruction handlers here. */ - -/* Here's ARMulator's DSP definition. A few things to note: - 1) it has 16 64-bit registers and 4 72-bit accumulators - 2) you can only access its registers with MCR and MRC. */ - -/* We can't define these in here because this file might not be linked - unless the target is arm9e-*. They are defined in wrapper.c. - Eventually the simulator should be made to handle any coprocessor - at run time. */ -struct maverick_regs -{ - union - { - int i; - float f; - } upper; - - union - { - int i; - float f; - } lower; -}; - -union maverick_acc_regs -{ - long double ld; /* Acc registers are 72-bits. */ -}; - -struct maverick_regs DSPregs[16]; -union maverick_acc_regs DSPacc[4]; -ARMword DSPsc; - -#define DEST_REG (BITS (12, 15)) -#define SRC1_REG (BITS (16, 19)) -#define SRC2_REG (BITS (0, 3)) - -static int lsw_int_index, msw_int_index; -static int lsw_float_index, msw_float_index; - -static double mv_getRegDouble (int); -static long long mv_getReg64int (int); -static void mv_setRegDouble (int, double val); -static void mv_setReg64int (int, long long val); - -static union -{ - double d; - long long ll; - int ints[2]; -} reg_conv; - -static void -printf_nothing (const char *foo, ...) -{ -} - -static void -cirrus_not_implemented (const char *insn) -{ - fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn); - fprintf (stderr, "aborting!\n"); - - // skyeye_exit (1); -} - -static unsigned -DSPInit (ARMul_State * state) -{ - NOTICE_LOG(ARM11, "ARMul_ConsolePrint: DSP present"); - return TRUE; -} - -unsigned -DSPMRC4 (ARMul_State * state, - unsigned type, ARMword instr, ARMword * value) -{ - switch (BITS (5, 7)) { - case 0: /* cfmvrdl */ - /* Move lower half of a DF stored in a DSP reg into an Arm reg. */ - printfdbg ("cfmvrdl\n"); - printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i); - printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); - - *value = (ARMword) DSPregs[SRC1_REG].lower.i; - break; - - case 1: /* cfmvrdh */ - /* Move upper half of a DF stored in a DSP reg into an Arm reg. */ - printfdbg ("cfmvrdh\n"); - printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i); - printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); - - *value = (ARMword) DSPregs[SRC1_REG].upper.i; - break; - - case 2: /* cfmvrs */ - /* Move SF from upper half of a DSP register to an Arm register. */ - *value = (ARMword) DSPregs[SRC1_REG].upper.i; - printfdbg ("cfmvrs = mvf%d <-- %f\n", - SRC1_REG, DSPregs[SRC1_REG].upper.f); - break; - -#ifdef doesnt_work - case 4: /* cfcmps */ - { - float a, b; - int n, z, c, v; - - a = DSPregs[SRC1_REG].upper.f; - b = DSPregs[SRC2_REG].upper.f; - - printfdbg ("cfcmps\n"); - printfdbg ("\tcomparing %f and %f\n", a, b); - - z = a == b; /* zero */ - n = a != b; /* negative */ - v = a > b; /* overflow */ - c = 0; /* carry */ - *value = (n << 31) | (z << 30) | (c << 29) | (v << - 28); - break; - } - - case 5: /* cfcmpd */ - { - double a, b; - int n, z, c, v; - - a = mv_getRegDouble (SRC1_REG); - b = mv_getRegDouble (SRC2_REG); - - printfdbg ("cfcmpd\n"); - printfdbg ("\tcomparing %g and %g\n", a, b); - - z = a == b; /* zero */ - n = a != b; /* negative */ - v = a > b; /* overflow */ - c = 0; /* carry */ - *value = (n << 31) | (z << 30) | (c << 29) | (v << - 28); - break; - } -#else - case 4: /* cfcmps */ - { - float a, b; - int n, z, c, v; - - a = DSPregs[SRC1_REG].upper.f; - b = DSPregs[SRC2_REG].upper.f; - - printfdbg ("cfcmps\n"); - printfdbg ("\tcomparing %f and %f\n", a, b); - - z = a == b; /* zero */ - n = a < b; /* negative */ - c = a > b; /* carry */ - v = 0; /* fixme */ - printfdbg ("\tz = %d, n = %d\n", z, n); - *value = (n << 31) | (z << 30) | (c << 29) | (v << - 28); - break; - } - - case 5: /* cfcmpd */ - { - double a, b; - int n, z, c, v; - - a = mv_getRegDouble (SRC1_REG); - b = mv_getRegDouble (SRC2_REG); - - printfdbg ("cfcmpd\n"); - printfdbg ("\tcomparing %g and %g\n", a, b); - - z = a == b; /* zero */ - n = a < b; /* negative */ - c = a > b; /* carry */ - v = 0; /* fixme */ - *value = (n << 31) | (z << 30) | (c << 29) | (v << - 28); - break; - } -#endif - default: - fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr); - cirrus_not_implemented ("unknown"); - break; - } - - return ARMul_DONE; -} - -unsigned -DSPMRC5 (ARMul_State * state, - unsigned type, ARMword instr, ARMword * value) -{ - switch (BITS (5, 7)) { - case 0: /* cfmvr64l */ - /* Move lower half of 64bit int from Cirrus to Arm. */ - *value = (ARMword) DSPregs[SRC1_REG].lower.i; - printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n", - DEST_REG, (int) *value); - break; - - case 1: /* cfmvr64h */ - /* Move upper half of 64bit int from Cirrus to Arm. */ - *value = (ARMword) DSPregs[SRC1_REG].upper.i; - printfdbg ("cfmvr64h <-- %d\n", (int) *value); - break; - - case 4: /* cfcmp32 */ - { - int res; - int n, z, c, v; - unsigned int a, b; - - printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", SRC1_REG, - SRC2_REG); - - /* FIXME: see comment for cfcmps. */ - a = DSPregs[SRC1_REG].lower.i; - b = DSPregs[SRC2_REG].lower.i; - - res = DSPregs[SRC1_REG].lower.i - - DSPregs[SRC2_REG].lower.i; - /* zero */ - z = res == 0; - /* negative */ - n = res < 0; - /* overflow */ - v = SubOverflow (DSPregs[SRC1_REG].lower.i, - DSPregs[SRC2_REG].lower.i, res); - /* carry */ - c = (NEG (a) && POS (b) || - (NEG (a) && POS (res)) || (POS (b) - && POS (res))); - - *value = (n << 31) | (z << 30) | (c << 29) | (v << - 28); - break; - } - - case 5: /* cfcmp64 */ - { - long long res; - int n, z, c, v; - unsigned long long a, b; - - printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", SRC1_REG, - SRC2_REG); - - /* fixme: see comment for cfcmps. */ - - a = mv_getReg64int (SRC1_REG); - b = mv_getReg64int (SRC2_REG); - - res = mv_getReg64int (SRC1_REG) - - mv_getReg64int (SRC2_REG); - /* zero */ - z = res == 0; - /* negative */ - n = res < 0; - /* overflow */ - v = ((NEG64 (a) && POS64 (b) && POS64 (res)) - || (POS64 (a) && NEG64 (b) && NEG64 (res))); - /* carry */ - c = (NEG64 (a) && POS64 (b) || - (NEG64 (a) && POS64 (res)) || (POS64 (b) - && POS64 (res))); - - *value = (n << 31) | (z << 30) | (c << 29) | (v << - 28); - break; - } - - default: - fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr); - cirrus_not_implemented ("unknown"); - break; - } - - return ARMul_DONE; -} - -unsigned -DSPMRC6 (ARMul_State * state, - unsigned type, ARMword instr, ARMword * value) -{ - switch (BITS (5, 7)) { - case 0: /* cfmval32 */ - cirrus_not_implemented ("cfmval32"); - break; - - case 1: /* cfmvam32 */ - cirrus_not_implemented ("cfmvam32"); - break; - - case 2: /* cfmvah32 */ - cirrus_not_implemented ("cfmvah32"); - break; - - case 3: /* cfmva32 */ - cirrus_not_implemented ("cfmva32"); - break; - - case 4: /* cfmva64 */ - cirrus_not_implemented ("cfmva64"); - break; - - case 5: /* cfmvsc32 */ - cirrus_not_implemented ("cfmvsc32"); - break; - - default: - fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr); - cirrus_not_implemented ("unknown"); - break; - } - - return ARMul_DONE; -} - -unsigned -DSPMCR4 (ARMul_State * state, - unsigned type, ARMword instr, ARMword value) -{ - switch (BITS (5, 7)) { - case 0: /* cfmvdlr */ - /* Move the lower half of a DF value from an Arm register into - the lower half of a Cirrus register. */ - printfdbg ("cfmvdlr <-- 0x%x\n", (int) value); - DSPregs[SRC1_REG].lower.i = (int) value; - break; - - case 1: /* cfmvdhr */ - /* Move the upper half of a DF value from an Arm register into - the upper half of a Cirrus register. */ - printfdbg ("cfmvdhr <-- 0x%x\n", (int) value); - DSPregs[SRC1_REG].upper.i = (int) value; - break; - - case 2: /* cfmvsr */ - /* Move SF from Arm register into upper half of Cirrus register. */ - printfdbg ("cfmvsr <-- 0x%x\n", (int) value); - DSPregs[SRC1_REG].upper.i = (int) value; - break; - - default: - fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr); - cirrus_not_implemented ("unknown"); - break; - } - - return ARMul_DONE; -} - -unsigned -DSPMCR5 (ARMul_State * state, - unsigned type, ARMword instr, ARMword value) -{ - union - { - int s; - unsigned int us; - } val; - - switch (BITS (5, 7)) { - case 0: /* cfmv64lr */ - /* Move lower half of a 64bit int from an ARM register into the - lower half of a DSP register and sign extend it. */ - printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG, - (int) value); - DSPregs[SRC1_REG].lower.i = (int) value; - break; - - case 1: /* cfmv64hr */ - /* Move upper half of a 64bit int from an ARM register into the - upper half of a DSP register. */ - printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n", - SRC1_REG, (int) value); - DSPregs[SRC1_REG].upper.i = (int) value; - break; - - case 2: /* cfrshl32 */ - printfdbg ("cfrshl32\n"); - val.us = value; - if (val.s > 0) - DSPregs[SRC2_REG].lower.i = - DSPregs[SRC1_REG].lower.i << value; - else - DSPregs[SRC2_REG].lower.i = - DSPregs[SRC1_REG].lower.i >> -value; - break; - - case 3: /* cfrshl64 */ - printfdbg ("cfrshl64\n"); - val.us = value; - if (val.s > 0) - mv_setReg64int (SRC2_REG, - mv_getReg64int (SRC1_REG) << value); - else - mv_setReg64int (SRC2_REG, - mv_getReg64int (SRC1_REG) >> -value); - break; - - default: - fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr); - cirrus_not_implemented ("unknown"); - break; - } - - return ARMul_DONE; -} - -unsigned -DSPMCR6 (ARMul_State * state, - unsigned type, ARMword instr, ARMword value) -{ - switch (BITS (5, 7)) { - case 0: /* cfmv32al */ - cirrus_not_implemented ("cfmv32al"); - break; - - case 1: /* cfmv32am */ - cirrus_not_implemented ("cfmv32am"); - break; - - case 2: /* cfmv32ah */ - cirrus_not_implemented ("cfmv32ah"); - break; - - case 3: /* cfmv32a */ - cirrus_not_implemented ("cfmv32a"); - break; - - case 4: /* cfmv64a */ - cirrus_not_implemented ("cfmv64a"); - break; - - case 5: /* cfmv32sc */ - cirrus_not_implemented ("cfmv32sc"); - break; - - default: - fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr); - cirrus_not_implemented ("unknown"); - break; - } - - return ARMul_DONE; -} - -unsigned -DSPLDC4 (ARMul_State * state, - unsigned type, ARMword instr, ARMword data) -{ - static unsigned words; - - if (type != ARMul_DATA) { - words = 0; - return ARMul_DONE; - } - - if (BIT (22)) { /* it's a long access, get two words */ - /* cfldrd */ - - printfdbg - ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n", - data, words, state->bigendSig, DEST_REG); - - if (words == 0) { - if (state->bigendSig) - DSPregs[DEST_REG].upper.i = (int) data; - else - DSPregs[DEST_REG].lower.i = (int) data; - } - else { - if (state->bigendSig) - DSPregs[DEST_REG].lower.i = (int) data; - else - DSPregs[DEST_REG].upper.i = (int) data; - } - - ++words; - - if (words == 2) { - printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG, - mv_getRegDouble (DEST_REG)); - - return ARMul_DONE; - } - else - return ARMul_INC; - } - else { - /* Get just one word. */ - - /* cfldrs */ - printfdbg ("cfldrs\n"); - - DSPregs[DEST_REG].upper.i = (int) data; - - printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG, - DSPregs[DEST_REG].upper.f); - - return ARMul_DONE; - } -} - -unsigned -DSPLDC5 (ARMul_State * state, - unsigned type, ARMword instr, ARMword data) -{ - static unsigned words; - - if (type != ARMul_DATA) { - words = 0; - return ARMul_DONE; - } - - if (BIT (22)) { - /* It's a long access, get two words. */ - - /* cfldr64 */ - printfdbg ("cfldr64: %d\n", data); - - if (words == 0) { - if (state->bigendSig) - DSPregs[DEST_REG].upper.i = (int) data; - else - DSPregs[DEST_REG].lower.i = (int) data; - } - else { - if (state->bigendSig) - DSPregs[DEST_REG].lower.i = (int) data; - else - DSPregs[DEST_REG].upper.i = (int) data; - } - - ++words; - - if (words == 2) { - printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG, - mv_getReg64int (DEST_REG)); - - return ARMul_DONE; - } - else - return ARMul_INC; - } - else { - /* Get just one word. */ - - /* cfldr32 */ - printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data); - - /* 32bit ints should be sign extended to 64bits when loaded. */ - mv_setReg64int (DEST_REG, (long long) data); - - return ARMul_DONE; - } -} - -unsigned -DSPSTC4 (ARMul_State * state, - unsigned type, ARMword instr, ARMword * data) -{ - static unsigned words; - - if (type != ARMul_DATA) { - words = 0; - return ARMul_DONE; - } - - if (BIT (22)) { - /* It's a long access, get two words. */ - /* cfstrd */ - printfdbg ("cfstrd\n"); - - if (words == 0) { - if (state->bigendSig) - *data = (ARMword) DSPregs[DEST_REG].upper.i; - else - *data = (ARMword) DSPregs[DEST_REG].lower.i; - } - else { - if (state->bigendSig) - *data = (ARMword) DSPregs[DEST_REG].lower.i; - else - *data = (ARMword) DSPregs[DEST_REG].upper.i; - } - - ++words; - - if (words == 2) { - printfdbg ("\tmem = mvd%d = %g\n", DEST_REG, - mv_getRegDouble (DEST_REG)); - - return ARMul_DONE; - } - else - return ARMul_INC; - } - else { - /* Get just one word. */ - /* cfstrs */ - printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG, - DSPregs[DEST_REG].upper.f); - - *data = (ARMword) DSPregs[DEST_REG].upper.i; - - return ARMul_DONE; - } -} - -unsigned -DSPSTC5 (ARMul_State * state, - unsigned type, ARMword instr, ARMword * data) -{ - static unsigned words; - - if (type != ARMul_DATA) { - words = 0; - return ARMul_DONE; - } - - if (BIT (22)) { - /* It's a long access, store two words. */ - /* cfstr64 */ - printfdbg ("cfstr64\n"); - - if (words == 0) { - if (state->bigendSig) - *data = (ARMword) DSPregs[DEST_REG].upper.i; - else - *data = (ARMword) DSPregs[DEST_REG].lower.i; - } - else { - if (state->bigendSig) - *data = (ARMword) DSPregs[DEST_REG].lower.i; - else - *data = (ARMword) DSPregs[DEST_REG].upper.i; - } - - ++words; - - if (words == 2) { - printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG, - mv_getReg64int (DEST_REG)); - - return ARMul_DONE; - } - else - return ARMul_INC; - } - else { - /* Store just one word. */ - /* cfstr32 */ - *data = (ARMword) DSPregs[DEST_REG].lower.i; - - printfdbg ("cfstr32 MEM = %d\n", (int) *data); - - return ARMul_DONE; - } -} - -unsigned -DSPCDP4 (ARMul_State * state, unsigned type, ARMword instr) -{ - int opcode2; - - opcode2 = BITS (5, 7); - - switch (BITS (20, 21)) { - case 0: - switch (opcode2) { - case 0: /* cfcpys */ - printfdbg ("cfcpys mvf%d = mvf%d = %f\n", - DEST_REG, SRC1_REG, - DSPregs[SRC1_REG].upper.f); - DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f; - break; - - case 1: /* cfcpyd */ - printfdbg ("cfcpyd mvd%d = mvd%d = %g\n", - DEST_REG, SRC1_REG, - mv_getRegDouble (SRC1_REG)); - mv_setRegDouble (DEST_REG, - mv_getRegDouble (SRC1_REG)); - break; - - case 2: /* cfcvtds */ - printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n", - DEST_REG, SRC1_REG, - (float) mv_getRegDouble (SRC1_REG)); - DSPregs[DEST_REG].upper.f = - (float) mv_getRegDouble (SRC1_REG); - break; - - case 3: /* cfcvtsd */ - printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n", - DEST_REG, SRC1_REG, - (double) DSPregs[SRC1_REG].upper.f); - mv_setRegDouble (DEST_REG, - (double) DSPregs[SRC1_REG].upper.f); - break; - - case 4: /* cfcvt32s */ - printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n", - DEST_REG, SRC1_REG, - (float) DSPregs[SRC1_REG].lower.i); - DSPregs[DEST_REG].upper.f = - (float) DSPregs[SRC1_REG].lower.i; - break; - - case 5: /* cfcvt32d */ - printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n", - DEST_REG, SRC1_REG, - (double) DSPregs[SRC1_REG].lower.i); - mv_setRegDouble (DEST_REG, - (double) DSPregs[SRC1_REG].lower.i); - break; - - case 6: /* cfcvt64s */ - printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n", - DEST_REG, SRC1_REG, - (float) mv_getReg64int (SRC1_REG)); - DSPregs[DEST_REG].upper.f = - (float) mv_getReg64int (SRC1_REG); - break; - - case 7: /* cfcvt64d */ - printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n", - DEST_REG, SRC1_REG, - (double) mv_getReg64int (SRC1_REG)); - mv_setRegDouble (DEST_REG, - (double) mv_getReg64int (SRC1_REG)); - break; - } - break; - - case 1: - switch (opcode2) { - case 0: /* cfmuls */ - printfdbg ("cfmuls mvf%d = mvf%d = %f\n", - DEST_REG, - SRC1_REG, - DSPregs[SRC1_REG].upper.f * - DSPregs[SRC2_REG].upper.f); - - DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f - * DSPregs[SRC2_REG].upper.f; - break; - - case 1: /* cfmuld */ - printfdbg ("cfmuld mvd%d = mvd%d = %g\n", - DEST_REG, - SRC1_REG, - mv_getRegDouble (SRC1_REG) * - mv_getRegDouble (SRC2_REG)); - - mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) - * mv_getRegDouble (SRC2_REG)); - break; - - default: - fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", - instr); - cirrus_not_implemented ("unknown"); - break; - } - break; - - case 3: - switch (opcode2) { - case 0: /* cfabss */ - DSPregs[DEST_REG].upper.f = - (DSPregs[SRC1_REG].upper.f < - 0.0F ? -DSPregs[SRC1_REG].upper. - f : DSPregs[SRC1_REG].upper.f); - printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", DEST_REG, - SRC1_REG, DSPregs[DEST_REG].upper.f); - break; - - case 1: /* cfabsd */ - mv_setRegDouble (DEST_REG, - (mv_getRegDouble (SRC1_REG) < 0.0 ? - -mv_getRegDouble (SRC1_REG) - : mv_getRegDouble (SRC1_REG))); - printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n", - DEST_REG, SRC1_REG, - mv_getRegDouble (DEST_REG)); - break; - - case 2: /* cfnegs */ - DSPregs[DEST_REG].upper.f = - -DSPregs[SRC1_REG].upper.f; - printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", DEST_REG, - SRC1_REG, DSPregs[DEST_REG].upper.f); - break; - - case 3: /* cfnegd */ - mv_setRegDouble (DEST_REG, - -mv_getRegDouble (SRC1_REG)); - printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", DEST_REG, - mv_getRegDouble (DEST_REG)); - break; - - case 4: /* cfadds */ - DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f - + DSPregs[SRC2_REG].upper.f; - printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].upper.f); - break; - - case 5: /* cfaddd */ - mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) - + mv_getRegDouble (SRC2_REG)); - printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n", - DEST_REG, - SRC1_REG, SRC2_REG, - mv_getRegDouble (DEST_REG)); - break; - - case 6: /* cfsubs */ - DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f - - DSPregs[SRC2_REG].upper.f; - printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].upper.f); - break; - - case 7: /* cfsubd */ - mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG) - - mv_getRegDouble (SRC2_REG)); - printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n", - DEST_REG, - SRC1_REG, SRC2_REG, - mv_getRegDouble (DEST_REG)); - break; - } - break; - - default: - fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr); - cirrus_not_implemented ("unknown"); - break; - } - - return ARMul_DONE; -} - -unsigned -DSPCDP5 (ARMul_State * state, unsigned type, ARMword instr) -{ - int opcode2; - char shift; - - opcode2 = BITS (5, 7); - - /* Shift constants are 7bit signed numbers in bits 0..3|5..7. */ - shift = BITS (0, 3) | (BITS (5, 7)) << 4; - if (shift & 0x40) - shift |= 0xc0; - - switch (BITS (20, 21)) { - case 0: - /* cfsh32 */ - printfdbg ("cfsh32 %s amount=%d\n", - shift < 0 ? "right" : "left", shift); - if (shift < 0) - /* Negative shift is a right shift. */ - DSPregs[DEST_REG].lower.i = - DSPregs[SRC1_REG].lower.i >> -shift; - else - /* Positive shift is a left shift. */ - DSPregs[DEST_REG].lower.i = - DSPregs[SRC1_REG].lower.i << shift; - break; - - case 1: - switch (opcode2) { - case 0: /* cfmul32 */ - DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i - * DSPregs[SRC2_REG].lower.i; - printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].lower.i); - break; - - case 1: /* cfmul64 */ - mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) - * mv_getReg64int (SRC2_REG)); - printfdbg - ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n", - DEST_REG, SRC1_REG, SRC2_REG, - mv_getReg64int (DEST_REG)); - break; - - case 2: /* cfmac32 */ - DSPregs[DEST_REG].lower.i - += - DSPregs[SRC1_REG].lower.i * - DSPregs[SRC2_REG].lower.i; - printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].lower.i); - break; - - case 3: /* cfmsc32 */ - DSPregs[DEST_REG].lower.i - -= - DSPregs[SRC1_REG].lower.i * - DSPregs[SRC2_REG].lower.i; - printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].lower.i); - break; - - case 4: /* cfcvts32 */ - /* fixme: this should round */ - DSPregs[DEST_REG].lower.i = - (int) DSPregs[SRC1_REG].upper.f; - printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", DEST_REG, - SRC1_REG, DSPregs[DEST_REG].lower.i); - break; - - case 5: /* cfcvtd32 */ - /* fixme: this should round */ - DSPregs[DEST_REG].lower.i = - (int) mv_getRegDouble (SRC1_REG); - printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", DEST_REG, - SRC1_REG, DSPregs[DEST_REG].lower.i); - break; - - case 6: /* cftruncs32 */ - DSPregs[DEST_REG].lower.i = - (int) DSPregs[SRC1_REG].upper.f; - printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n", - DEST_REG, SRC1_REG, - DSPregs[DEST_REG].lower.i); - break; - - case 7: /* cftruncd32 */ - DSPregs[DEST_REG].lower.i = - (int) mv_getRegDouble (SRC1_REG); - printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n", - DEST_REG, SRC1_REG, - DSPregs[DEST_REG].lower.i); - break; - } - break; - - case 2: - /* cfsh64 */ - printfdbg ("cfsh64\n"); - - if (shift < 0) - /* Negative shift is a right shift. */ - mv_setReg64int (DEST_REG, - mv_getReg64int (SRC1_REG) >> -shift); - else - /* Positive shift is a left shift. */ - mv_setReg64int (DEST_REG, - mv_getReg64int (SRC1_REG) << shift); - printfdbg ("\t%llx\n", mv_getReg64int (DEST_REG)); - break; - - case 3: - switch (opcode2) { - case 0: /* cfabs32 */ - DSPregs[DEST_REG].lower.i = - (DSPregs[SRC1_REG].lower.i < - 0 ? -DSPregs[SRC1_REG].lower. - i : DSPregs[SRC1_REG].lower.i); - printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].lower.i); - break; - - case 1: /* cfabs64 */ - mv_setReg64int (DEST_REG, - (mv_getReg64int (SRC1_REG) < 0 - ? -mv_getReg64int (SRC1_REG) - : mv_getReg64int (SRC1_REG))); - printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n", - DEST_REG, SRC1_REG, SRC2_REG, - mv_getReg64int (DEST_REG)); - break; - - case 2: /* cfneg32 */ - DSPregs[DEST_REG].lower.i = - -DSPregs[SRC1_REG].lower.i; - printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].lower.i); - break; - - case 3: /* cfneg64 */ - mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG)); - printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n", - DEST_REG, SRC1_REG, SRC2_REG, - mv_getReg64int (DEST_REG)); - break; - - case 4: /* cfadd32 */ - DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i - + DSPregs[SRC2_REG].lower.i; - printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].lower.i); - break; - - case 5: /* cfadd64 */ - mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) - + mv_getReg64int (SRC2_REG)); - printfdbg - ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n", - DEST_REG, SRC1_REG, SRC2_REG, - mv_getReg64int (DEST_REG)); - break; - - case 6: /* cfsub32 */ - DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i - - DSPregs[SRC2_REG].lower.i; - printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n", - DEST_REG, SRC1_REG, SRC2_REG, - DSPregs[DEST_REG].lower.i); - break; - - case 7: /* cfsub64 */ - mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG) - - mv_getReg64int (SRC2_REG)); - printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n", - DEST_REG, SRC1_REG, SRC2_REG, - mv_getReg64int (DEST_REG)); - break; - } - break; - - default: - fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr); - cirrus_not_implemented ("unknown"); - break; - } - - return ARMul_DONE; -} - -unsigned -DSPCDP6 (ARMul_State * state, unsigned type, ARMword instr) -{ - int opcode2; - - opcode2 = BITS (5, 7); - - switch (BITS (20, 21)) { - case 0: - /* cfmadd32 */ - cirrus_not_implemented ("cfmadd32"); - break; - - case 1: - /* cfmsub32 */ - cirrus_not_implemented ("cfmsub32"); - break; - - case 2: - /* cfmadda32 */ - cirrus_not_implemented ("cfmadda32"); - break; - - case 3: - /* cfmsuba32 */ - cirrus_not_implemented ("cfmsuba32"); - break; - - default: - fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr); - } - - return ARMul_DONE; -} - -/* Conversion functions. - - 32-bit integers are stored in the LOWER half of a 64-bit physical - register. - - Single precision floats are stored in the UPPER half of a 64-bit - physical register. */ - -static double -mv_getRegDouble (int regnum) -{ - reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i; - reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i; - return reg_conv.d; -} - -static void -mv_setRegDouble (int regnum, double val) -{ - reg_conv.d = val; - DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index]; - DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index]; -} - -static long long -mv_getReg64int (int regnum) -{ - reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i; - reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i; - return reg_conv.ll; -} - -static void -mv_setReg64int (int regnum, long long val) -{ - reg_conv.ll = val; - DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index]; - DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index]; -} - -/* Compute LSW in a double and a long long. */ - -void -mv_compute_host_endianness (ARMul_State * state) -{ - static union - { - long long ll; - int ints[2]; - int i; - double d; - float floats[2]; - float f; - } conv; - - /* Calculate where's the LSW in a 64bit int. */ - conv.ll = 45; - - if (conv.ints[0] == 0) { - msw_int_index = 0; - lsw_int_index = 1; - } - else { - assert (conv.ints[1] == 0); - msw_int_index = 1; - lsw_int_index = 0; - } - - /* Calculate where's the LSW in a double. */ - conv.d = 3.0; - - if (conv.ints[0] == 0) { - msw_float_index = 0; - lsw_float_index = 1; - } - else { - assert (conv.ints[1] == 0); - msw_float_index = 1; - lsw_float_index = 0; - } - - printfdbg ("lsw_int_index %d\n", lsw_int_index); - printfdbg ("lsw_float_index %d\n", lsw_float_index); -} diff --git a/src/core/arm/interpreter/mmu/rb.cpp b/src/core/arm/interpreter/mmu/rb.cpp deleted file mode 100644 index 07b11e311..000000000 --- a/src/core/arm/interpreter/mmu/rb.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "core/arm/interpreter/armdefs.h" - -/*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu*/ -ARMword rb_masks[] = { - 0x0, //RB_INVALID - 4, //RB_1 - 16, //RB_4 - 32, //RB_8 -}; - -/*mmu_rb_init - * @rb_t :rb_t to init - * @num :number of entry - * */ -int -mmu_rb_init (rb_s * rb_t, int num) -{ - int i; - rb_entry_t *entrys; - - entrys = (rb_entry_t *) malloc (sizeof (*entrys) * num); - if (entrys == NULL) { - printf ("SKYEYE:mmu_rb_init malloc error\n"); - return -1; - } - for (i = 0; i < num; i++) { - entrys[i].type = RB_INVALID; - entrys[i].fault = NO_FAULT; - } - - rb_t->entrys = entrys; - rb_t->num = num; - return 0; -} - -/*mmu_rb_exit*/ -void -mmu_rb_exit (rb_s * rb_t) -{ - free (rb_t->entrys); -}; - -/*mmu_rb_search - * @rb_t :rb_t to serach - * @va :va address to math - * - * $ NULL :not match - * NO-NULL: - * */ -rb_entry_t * -mmu_rb_search (rb_s * rb_t, ARMword va) -{ - int i; - rb_entry_t *rb = rb_t->entrys; - - DEBUG_LOG(ARM11, "va = %x\n", va); - for (i = 0; i < rb_t->num; i++, rb++) { - //2004-06-06 lyh bug from wenye@cs.ucsb.edu - if (rb->type) { - if ((va >= rb->va) - && (va < (rb->va + rb_masks[rb->type]))) - return rb; - } - } - return NULL; -}; - -void -mmu_rb_invalidate_entry (rb_s * rb_t, int i) -{ - rb_t->entrys[i].type = RB_INVALID; -} - -void -mmu_rb_invalidate_all (rb_s * rb_t) -{ - int i; - - for (i = 0; i < rb_t->num; i++) - mmu_rb_invalidate_entry (rb_t, i); -}; - -void -mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, int type, ARMword va) -{ - rb_entry_t *rb; - int i; - ARMword max_start, min_end; - fault_t fault; - tlb_entry_t *tlb; - - /*align va according to type */ - va &= ~(rb_masks[type] - 1); - /*invalidate all RB match [va, va + rb_masks[type]] */ - for (rb = rb_t->entrys, i = 0; i < rb_t->num; i++, rb++) { - if (rb->type) { - max_start = max (va, rb->va); - min_end = - min (va + rb_masks[type], - rb->va + rb_masks[rb->type]); - if (max_start < min_end) - rb->type = RB_INVALID; - } - } - /*load word */ - rb = &rb_t->entrys[i_rb]; - rb->type = type; - fault = translate (state, va, D_TLB (), &tlb); - if (fault) { - rb->fault = fault; - return; - } - fault = check_access (state, va, tlb, 1); - if (fault) { - rb->fault = fault; - return; - } - - rb->fault = NO_FAULT; - va = tlb_va_to_pa (tlb, va); - //2004-06-06 lyh bug from wenye@cs.ucsb.edu - for (i = 0; i < (rb_masks[type] / 4); i++, va += WORD_SIZE) { - //rb->data[i] = mem_read_word (state, va); - bus_read(32, va, &rb->data[i]); - }; -} diff --git a/src/core/arm/interpreter/mmu/rb.h b/src/core/arm/interpreter/mmu/rb.h deleted file mode 100644 index 7bf0ebb26..000000000 --- a/src/core/arm/interpreter/mmu/rb.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _MMU_RB_H -#define _MMU_RB_H - -enum rb_type_t -{ - RB_INVALID = 0, //invalid - RB_1, //1 word - RB_4, //4 word - RB_8, //8 word -}; - -/*bytes of each rb_type*/ -extern ARMword rb_masks[]; - -#define RB_WORD_NUM 8 -typedef struct rb_entry_s -{ - ARMword data[RB_WORD_NUM]; //array to store data - ARMword va; //first word va - int type; //rb type - fault_t fault; //fault set by rb alloc -} rb_entry_t; - -typedef struct rb_s -{ - int num; - rb_entry_t *entrys; -} rb_s; - -/*mmu_rb_init - * @rb_t :rb_t to init - * @num :number of entry - * */ -int mmu_rb_init (rb_s * rb_t, int num); - -/*mmu_rb_exit*/ -void mmu_rb_exit (rb_s * rb_t); - - -/*mmu_rb_search - * @rb_t :rb_t to serach - * @va :va address to math - * - * $ NULL :not match - * NO-NULL: - * */ -rb_entry_t *mmu_rb_search (rb_s * rb_t, ARMword va); - - -void mmu_rb_invalidate_entry (rb_s * rb_t, int i); -void mmu_rb_invalidate_all (rb_s * rb_t); -void mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, - int type, ARMword va); - -#endif /*_MMU_RB_H_*/ diff --git a/src/core/arm/interpreter/mmu/sa_mmu.cpp b/src/core/arm/interpreter/mmu/sa_mmu.cpp deleted file mode 100644 index eff5002de..000000000 --- a/src/core/arm/interpreter/mmu/sa_mmu.cpp +++ /dev/null @@ -1,864 +0,0 @@ -/* - armmmu.c - Memory Management Unit emulation. - ARMulator extensions for the ARM7100 family. - Copyright (C) 1999 Ben Williamson - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <assert.h> -#include <string.h> - -#include "core/arm/interpreter/armdefs.h" - -/** - * The interface of read data from bus - */ -int bus_read(short size, int addr, uint32_t * value) { - ERROR_LOG(ARM11, "unimplemented bus_read"); - return 0; -} - -/** - * The interface of write data from bus - */ -int bus_write(short size, int addr, uint32_t value) { - ERROR_LOG(ARM11, "unimplemented bus_write"); - return 0; -} - - -typedef struct sa_mmu_desc_s -{ - int i_tlb; - cache_desc_t i_cache; - - int d_tlb; - cache_desc_t main_d_cache; - cache_desc_t mini_d_cache; - int rb; - wb_desc_t wb; -} sa_mmu_desc_t; - -static sa_mmu_desc_t sa11xx_mmu_desc = { - 32, - {32, 32, 16, CACHE_WRITE_BACK}, - - 32, - {32, 32, 8, CACHE_WRITE_BACK}, - {32, 2, 8, CACHE_WRITE_BACK}, - 4, - //{8, 4}, for word size - {8, 16}, //for byte size, chy 2003-07-11 -}; - -static fault_t sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, - ARMword datatype); -static fault_t sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data, - ARMword datatype); -static fault_t update_cache (ARMul_State * state, ARMword va, ARMword data, - ARMword datatype, cache_line_t * cache, - cache_s * cache_t, ARMword real_va); - -void -mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa, - ARMbyte * data, int n); -int -sa_mmu_init (ARMul_State * state) -{ - sa_mmu_desc_t *desc; - cache_desc_t *c_desc; - - state->mmu.control = 0x70; - state->mmu.translation_table_base = 0xDEADC0DE; - state->mmu.domain_access_control = 0xDEADC0DE; - state->mmu.fault_status = 0; - state->mmu.fault_address = 0; - state->mmu.process_id = 0; - - desc = &sa11xx_mmu_desc; - if (mmu_tlb_init (I_TLB (), desc->i_tlb)) { - ERROR_LOG(ARM11, "i_tlb init %d\n", -1); - goto i_tlb_init_error; - } - - c_desc = &desc->i_cache; - if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way, - c_desc->set, c_desc->w_mode)) { - ERROR_LOG(ARM11, "i_cache init %d\n", -1); - goto i_cache_init_error; - } - - if (mmu_tlb_init (D_TLB (), desc->d_tlb)) { - ERROR_LOG(ARM11, "d_tlb init %d\n", -1); - goto d_tlb_init_error; - } - - c_desc = &desc->main_d_cache; - if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way, - c_desc->set, c_desc->w_mode)) { - ERROR_LOG(ARM11, "main_d_cache init %d\n", -1); - goto main_d_cache_init_error; - } - - c_desc = &desc->mini_d_cache; - if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way, - c_desc->set, c_desc->w_mode)) { - ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1); - goto mini_d_cache_init_error; - } - - if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) { - ERROR_LOG(ARM11, "wb init %d\n", -1); - goto wb_init_error; - } - - if (mmu_rb_init (RB (), desc->rb)) { - ERROR_LOG(ARM11, "rb init %d\n", -1); - goto rb_init_error; - } - return 0; - - rb_init_error: - mmu_wb_exit (WB ()); - wb_init_error: - mmu_cache_exit (MINI_D_CACHE ()); - mini_d_cache_init_error: - mmu_cache_exit (MAIN_D_CACHE ()); - main_d_cache_init_error: - mmu_tlb_exit (D_TLB ()); - d_tlb_init_error: - mmu_cache_exit (I_CACHE ()); - i_cache_init_error: - mmu_tlb_exit (I_TLB ()); - i_tlb_init_error: - return -1; -} - -void -sa_mmu_exit (ARMul_State * state) -{ - mmu_rb_exit (RB ()); - mmu_wb_exit (WB ()); - mmu_cache_exit (MINI_D_CACHE ()); - mmu_cache_exit (MAIN_D_CACHE ()); - mmu_tlb_exit (D_TLB ()); - mmu_cache_exit (I_CACHE ()); - mmu_tlb_exit (I_TLB ()); -}; - - -static fault_t -sa_mmu_load_instr (ARMul_State * state, ARMword va, ARMword * instr) -{ - fault_t fault; - tlb_entry_t *tlb; - cache_line_t *cache; - int c; //cache bit - ARMword pa; //physical addr - - static int debug_count = 0; //used for debug - - DEBUG_LOG(ARM11, "va = %x\n", va); - - va = mmu_pid_va_map (va); - if (MMU_Enabled) { - /*align check */ - if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } - else - va &= ~(WORD_SIZE - 1); - - /*translate tlb */ - fault = translate (state, va, I_TLB (), &tlb); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - return fault; - } - - /*check access */ - fault = check_access (state, va, tlb, 1); - if (fault) { - DEBUG_LOG(ARM11, "check_fault\n"); - return fault; - } - } - - /*search cache no matter MMU enabled/disabled */ - cache = mmu_cache_search (state, I_CACHE (), va); - if (cache) { - *instr = cache->data[va_cache_index (va, I_CACHE ())]; - return NO_FAULT; - } - - /*if MMU disabled or C flag is set alloc cache */ - if (MMU_Disabled) { - c = 1; - pa = va; - } - else { - c = tlb_c_flag (tlb); - pa = tlb_va_to_pa (tlb, va); - } - - if (c) { - int index; - - debug_count++; - cache = mmu_cache_alloc (state, I_CACHE (), va, pa); - index = va_cache_index (va, I_CACHE ()); - *instr = cache->data[va_cache_index (va, I_CACHE ())]; - } - else - //*instr = mem_read_word (state, pa); - bus_read(32, pa, instr); - - return NO_FAULT; -}; - - - -static fault_t -sa_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - //ARMword temp,offset; - fault_t fault; - fault = sa_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); - return fault; -} - -static fault_t -sa_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - //ARMword temp,offset; - fault_t fault; - fault = sa_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); - return fault; -} - -static fault_t -sa_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data) -{ - return sa_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); -} - - - - -static fault_t -sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data, - ARMword datatype) -{ - fault_t fault; - rb_entry_t *rb; - tlb_entry_t *tlb; - cache_line_t *cache; - ARMword pa, real_va, temp, offset; - - DEBUG_LOG(ARM11, "va = %x\n", va); - - va = mmu_pid_va_map (va); - real_va = va; - /*if MMU disabled, memory_read */ - if (MMU_Disabled) { - //*data = mem_read_word(state, va); - if (datatype == ARM_BYTE_TYPE) - //*data = mem_read_byte (state, va); - bus_read(8, va, data); - else if (datatype == ARM_HALFWORD_TYPE) - //*data = mem_read_halfword (state, va); - bus_read(16, va, data); - else if (datatype == ARM_WORD_TYPE) - //*data = mem_read_word (state, va); - bus_read(32, va, data); - else { - printf ("SKYEYE:1 sa_mmu_read error: unknown data type %d\n", datatype); - // skyeye_exit (-1); - } - - return NO_FAULT; - } - - /*align check */ - if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || - ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } // else - - va &= ~(WORD_SIZE - 1); - - /*translate va to tlb */ - fault = translate (state, va, D_TLB (), &tlb); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - return fault; - } - /*check access permission */ - fault = check_access (state, va, tlb, 1); - if (fault) - return fault; - /*search in read buffer */ - rb = mmu_rb_search (RB (), va); - if (rb) { - if (rb->fault) - return rb->fault; - *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT]; - goto datatrans; - //return 0; - }; - /*search main cache */ - cache = mmu_cache_search (state, MAIN_D_CACHE (), va); - if (cache) { - *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())]; - goto datatrans; - //return 0; - } - /*search mini cache */ - cache = mmu_cache_search (state, MINI_D_CACHE (), va); - if (cache) { - *data = cache->data[va_cache_index (va, MINI_D_CACHE ())]; - goto datatrans; - //return 0; - } - - /*get phy_addr */ - pa = tlb_va_to_pa (tlb, va); - if ((pa >= 0xe0000000) && (pa < 0xe8000000)) { - if (tlb_c_flag (tlb)) { - if (tlb_b_flag (tlb)) { - mmu_cache_soft_flush (state, MAIN_D_CACHE (), - pa); - } - else { - mmu_cache_soft_flush (state, MINI_D_CACHE (), - pa); - } - } - return NO_FAULT; - } - - /*if Buffer, drain Write Buffer first */ - if (tlb_b_flag (tlb)) - mmu_wb_drain_all (state, WB ()); - - /*alloc cache or mem_read */ - if (tlb_c_flag (tlb) && MMU_DCacheEnabled) { - cache_s *cache_t; - - if (tlb_b_flag (tlb)) - cache_t = MAIN_D_CACHE (); - else - cache_t = MINI_D_CACHE (); - cache = mmu_cache_alloc (state, cache_t, va, pa); - *data = cache->data[va_cache_index (va, cache_t)]; - } - else { - //*data = mem_read_word(state, pa); - if (datatype == ARM_BYTE_TYPE) - //*data = mem_read_byte (state, pa | (real_va & 3)); - bus_read(8, pa | (real_va & 3), data); - else if (datatype == ARM_HALFWORD_TYPE) - //*data = mem_read_halfword (state, pa | (real_va & 2)); - bus_read(16, pa | (real_va & 2), data); - else if (datatype == ARM_WORD_TYPE) - //*data = mem_read_word (state, pa); - bus_read(32, pa, data); - else { - printf ("SKYEYE:2 sa_mmu_read error: unknown data type %d\n", datatype); - // skyeye_exit (-1); - } - return NO_FAULT; - } - - - datatrans: - if (datatype == ARM_HALFWORD_TYPE) { - temp = *data; - offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ - *data = (temp >> offset) & 0xffff; - } - else if (datatype == ARM_BYTE_TYPE) { - temp = *data; - offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ - *data = (temp >> offset & 0xffL); - } - end: - return NO_FAULT; -} - - -static fault_t -sa_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - return sa_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); -} - -static fault_t -sa_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - return sa_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); -} - -static fault_t -sa_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data) -{ - return sa_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); -} - - - -static fault_t -sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, ARMword datatype) -{ - tlb_entry_t *tlb; - cache_line_t *cache; - int b; - ARMword pa, real_va; - fault_t fault; - - DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); - va = mmu_pid_va_map (va); - real_va = va; - - /*search instruction cache */ - cache = mmu_cache_search (state, I_CACHE (), va); - if (cache) { - update_cache (state, va, data, datatype, cache, I_CACHE (), - real_va); - } - - if (MMU_Disabled) { - //mem_write_word(state, va, data); - if (datatype == ARM_BYTE_TYPE) - //mem_write_byte (state, va, data); - bus_write(8, va, data); - else if (datatype == ARM_HALFWORD_TYPE) - //mem_write_halfword (state, va, data); - bus_write(16, va, data); - else if (datatype == ARM_WORD_TYPE) - //mem_write_word (state, va, data); - bus_write(32, va, data); - else { - printf ("SKYEYE:1 sa_mmu_write error: unknown data type %d\n", datatype); - // skyeye_exit (-1); - } - - return NO_FAULT; - } - /*align check */ - //if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ - if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || - ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } //else - va &= ~(WORD_SIZE - 1); - /*tlb translate */ - fault = translate (state, va, D_TLB (), &tlb); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - return fault; - } - /*tlb check access */ - fault = check_access (state, va, tlb, 0); - if (fault) { - DEBUG_LOG(ARM11, "check_access\n"); - return fault; - } - /*search main cache */ - cache = mmu_cache_search (state, MAIN_D_CACHE (), va); - if (cache) { - update_cache (state, va, data, datatype, cache, - MAIN_D_CACHE (), real_va); - } - else { - /*search mini cache */ - cache = mmu_cache_search (state, MINI_D_CACHE (), va); - if (cache) { - update_cache (state, va, data, datatype, cache, - MINI_D_CACHE (), real_va); - } - } - - if (!cache) { - b = tlb_b_flag (tlb); - pa = tlb_va_to_pa (tlb, va); - if (b) { - if (MMU_WBEnabled) { - if (datatype == ARM_WORD_TYPE) - mmu_wb_write_bytes (state, WB (), pa, - (ARMbyte*)&data, 4); - else if (datatype == ARM_HALFWORD_TYPE) - mmu_wb_write_bytes (state, WB (), - (pa | - (real_va & 2)), - (ARMbyte*)&data, 2); - else if (datatype == ARM_BYTE_TYPE) - mmu_wb_write_bytes (state, WB (), - (pa | - (real_va & 3)), - (ARMbyte*)&data, 1); - - } - else { - if (datatype == ARM_WORD_TYPE) - //mem_write_word (state, pa, data); - bus_write(32, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - /* - mem_write_halfword (state, - (pa | - (real_va & 2)), - data); - */ - bus_write(16, pa | (real_va & 2), data); - else if (datatype == ARM_BYTE_TYPE) - /* - mem_write_byte (state, - (pa | (real_va & 3)), - data); - */ - bus_write(8, pa | (real_va & 3), data); - } - } - else { - mmu_wb_drain_all (state, WB ()); - - if (datatype == ARM_WORD_TYPE) - //mem_write_word (state, pa, data); - bus_write(32, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - /* - mem_write_halfword (state, - (pa | (real_va & 2)), - data); - */ - bus_write(16, pa | (real_va & 2), data); - else if (datatype == ARM_BYTE_TYPE) - /* - mem_write_byte (state, (pa | (real_va & 3)), - data); - */ - bus_write(8, pa | (real_va & 3), data); - } - } - return NO_FAULT; -} - -static fault_t -update_cache (ARMul_State * state, ARMword va, ARMword data, ARMword datatype, - cache_line_t * cache, cache_s * cache_t, ARMword real_va) -{ - ARMword temp, offset; - - ARMword index = va_cache_index (va, cache_t); - - //cache->data[index] = data; - - if (datatype == ARM_WORD_TYPE) - cache->data[index] = data; - else if (datatype == ARM_HALFWORD_TYPE) { - temp = cache->data[index]; - offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ - cache->data[index] = - (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << - offset); - } - else if (datatype == ARM_BYTE_TYPE) { - temp = cache->data[index]; - offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ - cache->data[index] = - (temp & ~(0xffL << offset)) | ((data & 0xffL) << - offset); - } - - if (index < (cache_t->width >> (WORD_SHT + 1))) - cache->tag |= TAG_FIRST_HALF_DIRTY; - else - cache->tag |= TAG_LAST_HALF_DIRTY; - - return NO_FAULT; -} - -ARMword -sa_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) -{ - mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15); - ARMword data; - - switch (creg) { - case MMU_ID: -// printf("mmu_mrc read ID "); - data = 0x41007100; /* v3 */ - data = state->cpu->cpu_val; - break; - case MMU_CONTROL: -// printf("mmu_mrc read CONTROL"); - data = state->mmu.control; - break; - case MMU_TRANSLATION_TABLE_BASE: -// printf("mmu_mrc read TTB "); - data = state->mmu.translation_table_base; - break; - case MMU_DOMAIN_ACCESS_CONTROL: -// printf("mmu_mrc read DACR "); - data = state->mmu.domain_access_control; - break; - case MMU_FAULT_STATUS: -// printf("mmu_mrc read FSR "); - data = state->mmu.fault_status; - break; - case MMU_FAULT_ADDRESS: -// printf("mmu_mrc read FAR "); - data = state->mmu.fault_address; - break; - case MMU_PID: - data = state->mmu.process_id; - default: - printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); - data = 0; - break; - } -// printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); - *value = data; - return data; -} - -void -sa_mmu_cache_ops (ARMul_State * state, ARMword instr, ARMword value) -{ - int CRm, OPC_2; - - CRm = BITS (0, 3); - OPC_2 = BITS (5, 7); - - if (OPC_2 == 0 && CRm == 7) { - mmu_cache_invalidate_all (state, I_CACHE ()); - mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); - mmu_cache_invalidate_all (state, MINI_D_CACHE ()); - return; - } - - if (OPC_2 == 0 && CRm == 5) { - mmu_cache_invalidate_all (state, I_CACHE ()); - return; - } - - if (OPC_2 == 0 && CRm == 6) { - mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); - mmu_cache_invalidate_all (state, MINI_D_CACHE ()); - return; - } - - if (OPC_2 == 1 && CRm == 6) { - mmu_cache_invalidate (state, MAIN_D_CACHE (), value); - mmu_cache_invalidate (state, MINI_D_CACHE (), value); - return; - } - - if (OPC_2 == 1 && CRm == 0xa) { - mmu_cache_clean (state, MAIN_D_CACHE (), value); - mmu_cache_clean (state, MINI_D_CACHE (), value); - return; - } - - if (OPC_2 == 4 && CRm == 0xa) { - mmu_wb_drain_all (state, WB ()); - return; - } - ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); -} - -static void -sa_mmu_tlb_ops (ARMul_State * state, ARMword instr, ARMword value) -{ - int CRm, OPC_2; - - CRm = BITS (0, 3); - OPC_2 = BITS (5, 7); - - - if (OPC_2 == 0 && CRm == 0x7) { - mmu_tlb_invalidate_all (state, I_TLB ()); - mmu_tlb_invalidate_all (state, D_TLB ()); - return; - } - - if (OPC_2 == 0 && CRm == 0x5) { - mmu_tlb_invalidate_all (state, I_TLB ()); - return; - } - - if (OPC_2 == 0 && CRm == 0x6) { - mmu_tlb_invalidate_all (state, D_TLB ()); - return; - } - - if (OPC_2 == 1 && CRm == 0x6) { - mmu_tlb_invalidate_entry (state, D_TLB (), value); - return; - } - - ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); -} - -static void -sa_mmu_rb_ops (ARMul_State * state, ARMword instr, ARMword value) -{ - int CRm, OPC_2; - - CRm = BITS (0, 3); - OPC_2 = BITS (5, 7); - - if (OPC_2 == 0x0 && CRm == 0x0) { - mmu_rb_invalidate_all (RB ()); - return; - } - - if (OPC_2 == 0x2) { - int idx = CRm & 0x3; - int type = ((CRm >> 2) & 0x3) + 1; - - if ((idx < 4) && (type < 4)) - mmu_rb_load (state, RB (), idx, type, value); - return; - } - - if ((OPC_2 == 1) && (CRm < 4)) { - mmu_rb_invalidate_entry (RB (), CRm); - return; - } - - ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); -} - -static ARMword -sa_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) -{ - mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15); - if (!strncmp (state->cpu->cpu_arch_name, "armv4", 5)) { - switch (creg) { - case MMU_CONTROL: -// printf("mmu_mcr wrote CONTROL "); - state->mmu.control = (value | 0x70) & 0xFFFD; - break; - case MMU_TRANSLATION_TABLE_BASE: -// printf("mmu_mcr wrote TTB "); - state->mmu.translation_table_base = - value & 0xFFFFC000; - break; - case MMU_DOMAIN_ACCESS_CONTROL: -// printf("mmu_mcr wrote DACR "); - state->mmu.domain_access_control = value; - break; - - case MMU_FAULT_STATUS: - state->mmu.fault_status = value & 0xFF; - break; - case MMU_FAULT_ADDRESS: - state->mmu.fault_address = value; - break; - - case MMU_CACHE_OPS: - sa_mmu_cache_ops (state, instr, value); - break; - case MMU_TLB_OPS: - sa_mmu_tlb_ops (state, instr, value); - break; - case MMU_SA_RB_OPS: - sa_mmu_rb_ops (state, instr, value); - break; - case MMU_SA_DEBUG: - break; - case MMU_SA_CP15_R15: - break; - case MMU_PID: - //2004-06-06 lyh, bug provided by wen ye wenye@cs.ucsb.edu - state->mmu.process_id = value & 0x7e000000; - break; - - default: - printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); - break; - } - } - return 0; -} - -//teawater add for arm2x86 2005.06.24------------------------------------------- -static int -sa_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) -{ - fault_t fault; - tlb_entry_t *tlb; - - virt_addr = mmu_pid_va_map (virt_addr); - if (MMU_Enabled) { - - /*align check */ - if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } - else - virt_addr &= ~(WORD_SIZE - 1); - - /*translate tlb */ - fault = translate (state, virt_addr, I_TLB (), &tlb); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - return fault; - } - - /*check access */ - fault = check_access (state, virt_addr, tlb, 1); - if (fault) { - DEBUG_LOG(ARM11, "check_fault\n"); - return fault; - } - } - - if (MMU_Disabled) { - *phys_addr = virt_addr; - } - else { - *phys_addr = tlb_va_to_pa (tlb, virt_addr); - } - - return (0); -} - -//AJ2D-------------------------------------------------------------------------- - -/*sa mmu_ops_t*/ -mmu_ops_t sa_mmu_ops = { - sa_mmu_init, - sa_mmu_exit, - sa_mmu_read_byte, - sa_mmu_write_byte, - sa_mmu_read_halfword, - sa_mmu_write_halfword, - sa_mmu_read_word, - sa_mmu_write_word, - sa_mmu_load_instr, - sa_mmu_mcr, - sa_mmu_mrc, -//teawater add for arm2x86 2005.06.24------------------------------------------- - sa_mmu_v2p_dbct, -//AJ2D-------------------------------------------------------------------------- -}; diff --git a/src/core/arm/interpreter/mmu/sa_mmu.h b/src/core/arm/interpreter/mmu/sa_mmu.h deleted file mode 100644 index 64b1c5470..000000000 --- a/src/core/arm/interpreter/mmu/sa_mmu.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - sa_mmu.h - StrongARM Memory Management Unit emulation. - ARMulator extensions for SkyEye. - <lyhost@263.net> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifndef _SA_MMU_H_ -#define _SA_MMU_H_ - - -/** - * The interface of read data from bus - */ -int bus_read(short size, int addr, uint32_t * value); - -/** - * The interface of write data from bus - */ -int bus_write(short size, int addr, uint32_t value); - - -typedef struct sa_mmu_s -{ - tlb_s i_tlb; - cache_s i_cache; - - tlb_s d_tlb; - cache_s main_d_cache; - cache_s mini_d_cache; - rb_s rb_t; - wb_s wb_t; -} sa_mmu_t; - -#define I_TLB() (&state->mmu.u.sa_mmu.i_tlb) -#define I_CACHE() (&state->mmu.u.sa_mmu.i_cache) - -#define D_TLB() (&state->mmu.u.sa_mmu.d_tlb) -#define MAIN_D_CACHE() (&state->mmu.u.sa_mmu.main_d_cache) -#define MINI_D_CACHE() (&state->mmu.u.sa_mmu.mini_d_cache) -#define WB() (&state->mmu.u.sa_mmu.wb_t) -#define RB() (&state->mmu.u.sa_mmu.rb_t) - -extern mmu_ops_t sa_mmu_ops; -#endif /*_SA_MMU_H_*/ diff --git a/src/core/arm/interpreter/mmu/tlb.cpp b/src/core/arm/interpreter/mmu/tlb.cpp deleted file mode 100644 index ca60ac1a1..000000000 --- a/src/core/arm/interpreter/mmu/tlb.cpp +++ /dev/null @@ -1,307 +0,0 @@ -#include <assert.h> - -#include "core/arm/interpreter/armdefs.h" - -ARMword tlb_masks[] = { - 0x00000000, /* TLB_INVALID */ - 0xFFFFF000, /* TLB_SMALLPAGE */ - 0xFFFF0000, /* TLB_LARGEPAGE */ - 0xFFF00000, /* TLB_SECTION */ - 0xFFFFF000, /*TLB_ESMALLPAGE, have TEX attirbute, only for XScale */ - 0xFFFFFC00 /* TLB_TINYPAGE */ -}; - -/* This function encodes table 8-2 Interpreting AP bits, - returning non-zero if access is allowed. */ -static int -check_perms (ARMul_State * state, int ap, int read) -{ - int s, r, user; - - s = state->mmu.control & CONTROL_SYSTEM; - r = state->mmu.control & CONTROL_ROM; - //chy 2006-02-15 , should consider system mode, don't conside 26bit mode - user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); - - switch (ap) { - case 0: - return read && ((s && !user) || r); - case 1: - return !user; - case 2: - return read || !user; - case 3: - return 1; - } - return 0; -} - -fault_t -check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, - int read) -{ - int access; - - state->mmu.last_domain = tlb->domain; - access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; - if ((access == 0) || (access == 2)) { - /* It's unclear from the documentation whether this - should always raise a section domain fault, or if - it should be a page domain fault in the case of an - L1 that describes a page table. In the ARM710T - datasheets, "Figure 8-9: Sequence for checking faults" - seems to indicate the former, while "Table 8-4: Priority - encoding of fault status" gives a value for FS[3210] in - the event of a domain fault for a page. Hmm. */ - return SECTION_DOMAIN_FAULT; - } - if (access == 1) { - /* client access - check perms */ - int subpage, ap; - - switch (tlb->mapping) { - /*ks 2004-05-09 - * only for XScale - * Extend Small Page(ESP) Format - * 31-12 bits the base addr of ESP - * 11-10 bits SBZ - * 9-6 bits TEX - * 5-4 bits AP - * 3 bit C - * 2 bit B - * 1-0 bits 11 - * */ - case TLB_ESMALLPAGE: //xj - subpage = 0; - //printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); - break; - - case TLB_TINYPAGE: - subpage = 0; - //printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); - break; - - case TLB_SMALLPAGE: - subpage = (virt_addr >> 10) & 3; - break; - case TLB_LARGEPAGE: - subpage = (virt_addr >> 14) & 3; - break; - case TLB_SECTION: - subpage = 3; - break; - default: - assert (0); - subpage = 0; /* cleans a warning */ - } - ap = (tlb->perms >> (subpage * 2 + 4)) & 3; - if (!check_perms (state, ap, read)) { - if (tlb->mapping == TLB_SECTION) { - return SECTION_PERMISSION_FAULT; - } - else { - return SUBPAGE_PERMISSION_FAULT; - } - } - } - else { /* access == 3 */ - /* manager access - don't check perms */ - } - return NO_FAULT; -} - -fault_t -translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t, - tlb_entry_t ** tlb) -{ - *tlb = mmu_tlb_search (state, tlb_t, virt_addr); - if (!*tlb) { - /* walk the translation tables */ - ARMword l1addr, l1desc; - tlb_entry_t entry; - - l1addr = state->mmu.translation_table_base & 0xFFFFC000; - l1addr = (l1addr | (virt_addr >> 18)) & ~3; - //l1desc = mem_read_word (state, l1addr); - bus_read(32, l1addr, &l1desc); - switch (l1desc & 3) { - case 0: - /* - * according to Figure 3-9 Sequence for checking faults in arm manual, - * section translation fault should be returned here. - */ - { - return SECTION_TRANSLATION_FAULT; - } - case 3: - /* fine page table */ - // dcl 2006-01-08 - { - ARMword l2addr, l2desc; - - l2addr = l1desc & 0xFFFFF000; - l2addr = (l2addr | - ((virt_addr & 0x000FFC00) >> 8)) & - ~3; - //l2desc = mem_read_word (state, l2addr); - bus_read(32, l2addr, &l2desc); - - entry.virt_addr = virt_addr; - entry.phys_addr = l2desc; - entry.perms = l2desc & 0x00000FFC; - entry.domain = (l1desc >> 5) & 0x0000000F; - switch (l2desc & 3) { - case 0: - state->mmu.last_domain = entry.domain; - return PAGE_TRANSLATION_FAULT; - case 3: - entry.mapping = TLB_TINYPAGE; - break; - case 1: - // this is untested - entry.mapping = TLB_LARGEPAGE; - break; - case 2: - // this is untested - entry.mapping = TLB_SMALLPAGE; - break; - } - } - break; - case 1: - /* coarse page table */ - { - ARMword l2addr, l2desc; - - l2addr = l1desc & 0xFFFFFC00; - l2addr = (l2addr | - ((virt_addr & 0x000FF000) >> 10)) & - ~3; - //l2desc = mem_read_word (state, l2addr); - bus_read(32, l2addr, &l2desc); - - entry.virt_addr = virt_addr; - entry.phys_addr = l2desc; - entry.perms = l2desc & 0x00000FFC; - entry.domain = (l1desc >> 5) & 0x0000000F; - //printf("SKYEYE:PAGE virt_addr = %x,l1desc=%x,phys_addr=%x\n",virt_addr,l1desc,entry.phys_addr); - //chy 2003-09-02 for xscale - switch (l2desc & 3) { - case 0: - state->mmu.last_domain = entry.domain; - return PAGE_TRANSLATION_FAULT; - case 3: - if (!state->is_XScale) { - state->mmu.last_domain = - entry.domain; - return PAGE_TRANSLATION_FAULT; - }; - //ks 2004-05-09 xscale shold use Extend Small Page - //entry.mapping = TLB_SMALLPAGE; - entry.mapping = TLB_ESMALLPAGE; //xj - break; - case 1: - entry.mapping = TLB_LARGEPAGE; - break; - case 2: - entry.mapping = TLB_SMALLPAGE; - break; - } - } - break; - case 2: - /* section */ - //printf("SKYEYE:WARNING: not implement section mapping incompletely\n"); - //printf("SKYEYE:SECTION virt_addr = %x,l1desc=%x\n",virt_addr,l1desc); - //return SECTION_DOMAIN_FAULT; - //#if 0 - entry.virt_addr = virt_addr; - entry.phys_addr = l1desc; - entry.perms = l1desc & 0x00000C0C; - entry.domain = (l1desc >> 5) & 0x0000000F; - entry.mapping = TLB_SECTION; - break; - //#endif - } - entry.virt_addr &= tlb_masks[entry.mapping]; - entry.phys_addr &= tlb_masks[entry.mapping]; - - /* place entry in the tlb */ - *tlb = &tlb_t->entrys[tlb_t->cycle]; - tlb_t->cycle = (tlb_t->cycle + 1) % tlb_t->num; - **tlb = entry; - } - state->mmu.last_domain = (*tlb)->domain; - return NO_FAULT; -} - -int -mmu_tlb_init (tlb_s * tlb_t, int num) -{ - tlb_entry_t *e; - int i; - - e = (tlb_entry_t *) malloc (sizeof (*e) * num); - if (e == NULL) { - ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*e) * num); - goto tlb_malloc_error; - } - tlb_t->entrys = e; - for (i = 0; i < num; i++, e++) - e->mapping = TLB_INVALID; - tlb_t->cycle = 0; - tlb_t->num = num; - return 0; - - tlb_malloc_error: - return -1; -} - -void -mmu_tlb_exit (tlb_s * tlb_t) -{ - free (tlb_t->entrys); -}; - -void -mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t) -{ - int entry; - - for (entry = 0; entry < tlb_t->num; entry++) { - tlb_t->entrys[entry].mapping = TLB_INVALID; - } - tlb_t->cycle = 0; -} - -void -mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr) -{ - tlb_entry_t *tlb; - - tlb = mmu_tlb_search (state, tlb_t, addr); - if (tlb) { - tlb->mapping = TLB_INVALID; - } -} - -tlb_entry_t * -mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, ARMword virt_addr) -{ - int entry; - - for (entry = 0; entry < tlb_t->num; entry++) { - tlb_entry_t *tlb; - ARMword mask; - - tlb = &(tlb_t->entrys[entry]); - if (tlb->mapping == TLB_INVALID) { - continue; - } - mask = tlb_masks[tlb->mapping]; - if ((virt_addr & mask) == (tlb->virt_addr & mask)) { - return tlb; - } - } - return NULL; -} diff --git a/src/core/arm/interpreter/mmu/tlb.h b/src/core/arm/interpreter/mmu/tlb.h deleted file mode 100644 index 40856567b..000000000 --- a/src/core/arm/interpreter/mmu/tlb.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _MMU_TLB_H_ -#define _MMU_TLB_H_ - -typedef enum tlb_mapping_t -{ - TLB_INVALID = 0, - TLB_SMALLPAGE = 1, - TLB_LARGEPAGE = 2, - TLB_SECTION = 3, - TLB_ESMALLPAGE = 4, - TLB_TINYPAGE = 5 -} tlb_mapping_t; - -extern ARMword tlb_masks[]; - -/* Permissions bits in a TLB entry: - * - * 31 12 11 10 9 8 7 6 5 4 3 2 1 0 - * +-------------+-----+-----+-----+-----+---+---+-------+ - * Page:| | ap3 | ap2 | ap1 | ap0 | C | B | | - * +-------------+-----+-----+-----+-----+---+---+-------+ - * - * 31 12 11 10 9 4 3 2 1 0 - * +-------------+-----+-----------------+---+---+-------+ - * Section: | | AP | | C | B | | - * +-------------+-----+-----------------+---+---+-------+ - */ - -/* -section: - section base address [31:20] - AP - table 8-2, page 8-8 - domain - C,B - -page: - page base address [31:16] or [31:12] - ap[3:0] - domain (from L1) - C,B -*/ - - -typedef struct tlb_entry_t -{ - ARMword virt_addr; - ARMword phys_addr; - ARMword perms; - ARMword domain; - tlb_mapping_t mapping; -} tlb_entry_t; - -typedef struct tlb_s -{ - int num; /*num of tlb entry */ - int cycle; /*current tlb cycle */ - tlb_entry_t *entrys; -} tlb_s; - - -#define tlb_c_flag(tlb) \ - ((tlb)->perms & 0x8) -#define tlb_b_flag(tlb) \ - ((tlb)->perms & 0x4) - -#define tlb_va_to_pa(tlb, va) ((tlb->phys_addr & tlb_masks[tlb->mapping]) | (va & ~tlb_masks[tlb->mapping])) -fault_t -check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, - int read); - -fault_t -translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t, - tlb_entry_t ** tlb); - -int mmu_tlb_init (tlb_s * tlb_t, int num); - -void mmu_tlb_exit (tlb_s * tlb_t); - -void mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t); - -void -mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr); - -tlb_entry_t *mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, - ARMword virt_addr); - -#endif /*_MMU_TLB_H_*/ diff --git a/src/core/arm/interpreter/mmu/wb.cpp b/src/core/arm/interpreter/mmu/wb.cpp deleted file mode 100644 index 82c0cec02..000000000 --- a/src/core/arm/interpreter/mmu/wb.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "core/arm/interpreter/armdefs.h" - -/* wb_init - * @wb_t :wb_t to init - * @num :num of entrys - * @nb :num of byte of each entry - * - * $ -1:error - * 0:ok - * */ -int -mmu_wb_init (wb_s * wb_t, int num, int nb) -{ - int i; - wb_entry_t *entrys, *wb; - - entrys = (wb_entry_t *) malloc (sizeof (*entrys) * num); - if (entrys == NULL) { - ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*entrys) * num); - goto entrys_malloc_error; - } - - for (wb = entrys, i = 0; i < num; i++, wb++) { - /*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu */ - //wb->data = (ARMword *)malloc(sizeof(ARMword) * nb); - wb->data = (ARMbyte *) malloc (nb); - if (wb->data == NULL) { - ERROR_LOG(ARM11, "malloc size of %d\n", nb); - goto data_malloc_error; - } - - }; - - wb_t->first = wb_t->last = wb_t->used = 0; - wb_t->num = num; - wb_t->nb = nb; - wb_t->entrys = entrys; - return 0; - - data_malloc_error: - while (--i >= 0) - free (entrys[i].data); - free (entrys); - entrys_malloc_error: - return -1; -}; - -/* wb_exit - * @wb_t :wb_t to exit - * */ -void -mmu_wb_exit (wb_s * wb_t) -{ - int i; - wb_entry_t *wb; - - wb = wb_t->entrys; - for (i = 0; i < wb_t->num; i++, wb++) { - free (wb->data); - } - free (wb_t->entrys); -}; - -/* wb_write_words :put words in Write Buffer - * @state: ARMul_State - * @wb_t: write buffer - * @pa: physical address - * @data: data ptr - * @n number of word to write - * - * Note: write buffer merge is not implemented, can be done late - * */ -void -mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa, - ARMbyte * data, int n) -{ - int i; - wb_entry_t *wb; - - while (n) { - if (wb_t->num == wb_t->used) { - /*clean the last wb entry */ - ARMword t; - - wb = &wb_t->entrys[wb_t->last]; - t = wb->pa; - for (i = 0; i < wb->nb; i++) { - //mem_write_byte (state, t, wb->data[i]); - bus_write(8, t, wb->data[i]); - //t += WORD_SIZE; - t++; - } - wb_t->last++; - if (wb_t->last == wb_t->num) - wb_t->last = 0; - wb_t->used--; - } - - wb = &wb_t->entrys[wb_t->first]; - i = (n < wb_t->nb) ? n : wb_t->nb; - - wb->pa = pa; - //pa += i << WORD_SHT; - pa += i; - - wb->nb = i; - //memcpy(wb->data, data, i << WORD_SHT); - memcpy (wb->data, data, i); - data += i; - n -= i; - wb_t->first++; - if (wb_t->first == wb_t->num) - wb_t->first = 0; - wb_t->used++; - }; -//teawater add for set_dirty fflash cache function 2005.07.18------------------- -#ifdef DBCT - if (!skyeye_config.no_dbct) { - tb_setdirty (state, pa, NULL); - } -#endif -//AJ2D-------------------------------------------------------------------------- -} - -/* wb_drain_all - * @wb_t wb_t to drain - * */ -void -mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t) -{ - ARMword pa; - wb_entry_t *wb; - int i; - - while (wb_t->used) { - wb = &wb_t->entrys[wb_t->last]; - pa = wb->pa; - for (i = 0; i < wb->nb; i++) { - //mem_write_byte (state, pa, wb->data[i]); - bus_write(8, pa, wb->data[i]); - //pa += WORD_SIZE; - pa++; - } - wb_t->last++; - if (wb_t->last == wb_t->num) - wb_t->last = 0; - wb_t->used--; - }; -} diff --git a/src/core/arm/interpreter/mmu/wb.h b/src/core/arm/interpreter/mmu/wb.h deleted file mode 100644 index 8fb7de946..000000000 --- a/src/core/arm/interpreter/mmu/wb.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _MMU_WB_H_ -#define _MMU_WB_H_ - -typedef struct wb_entry_s -{ - ARMword pa; //phy_addr - ARMbyte *data; //data - int nb; //number byte to write -} wb_entry_t; - -typedef struct wb_s -{ - int num; //number of wb_entry - int nb; //number of byte of each entry - int first; // - int last; // - int used; // - wb_entry_t *entrys; -} wb_s; - -typedef struct wb_desc_s -{ - int num; - int nb; -} wb_desc_t; - -/* wb_init - * @wb_t :wb_t to init - * @num :num of entrys - * @nw :num of word of each entry - * - * $ -1:error - * 0:ok - * */ -int mmu_wb_init (wb_s * wb_t, int num, int nb); - - -/* wb_exit - * @wb_t :wb_t to exit - * */ -void mmu_wb_exit (wb_s * wb); - - -/* wb_write_bytes :put bytess in Write Buffer - * @state: ARMul_State - * @wb_t: write buffer - * @pa: physical address - * @data: data ptr - * @n number of byte to write - * - * Note: write buffer merge is not implemented, can be done late - * */ -void -mmu_wb_write_bytess (ARMul_State * state, wb_s * wb_t, ARMword pa, - ARMbyte * data, int n); - - -/* wb_drain_all - * @wb_t wb_t to drain - * */ -void mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t); - -#endif /*_MMU_WB_H_*/ diff --git a/src/core/arm/interpreter/mmu/xscale_copro.cpp b/src/core/arm/interpreter/mmu/xscale_copro.cpp deleted file mode 100644 index 433ce8e02..000000000 --- a/src/core/arm/interpreter/mmu/xscale_copro.cpp +++ /dev/null @@ -1,1391 +0,0 @@ -/* - armmmu.c - Memory Management Unit emulation. - ARMulator extensions for the ARM7100 family. - Copyright (C) 1999 Ben Williamson - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include <assert.h> -#include <string.h> - -#include "core/arm/interpreter/armdefs.h" -#include "core/arm/interpreter/armemu.h" - -/*#include "pxa.h" */ - -/* chy 2005-09-19 */ - -/* extern pxa270_io_t pxa270_io; */ -/* chy 2005-09-19 -----end */ - -typedef struct xscale_mmu_desc_s -{ - int i_tlb; - cache_desc_t i_cache; - - int d_tlb; - cache_desc_t main_d_cache; - cache_desc_t mini_d_cache; - //int rb; xscale has no read buffer - wb_desc_t wb; -} xscale_mmu_desc_t; - -static xscale_mmu_desc_t pxa_mmu_desc = { - 32, - {32, 32, 32, CACHE_WRITE_BACK}, - - 32, - {32, 32, 32, CACHE_WRITE_BACK}, - {32, 2, 8, CACHE_WRITE_BACK}, - {8, 16}, //for byte size, -}; - -//chy 2005-09-19 for cp6 -#define CR0_ICIP 0 -#define CR1_ICMR 1 -//chy 2005-09-19 ---end -//----------- for cp14----------------- -#define CCLKCFG 6 -#define PWRMODE 7 -typedef struct xscale_cp14_reg_s -{ - unsigned cclkcfg; //reg6 - unsigned pwrmode; //reg7 -} xscale_cp14_reg_s; - -xscale_cp14_reg_s pxa_cp14_regs; - -//-------------------------------------- - -static fault_t xscale_mmu_write (ARMul_State * state, ARMword va, - ARMword data, ARMword datatype); -static fault_t xscale_mmu_read (ARMul_State * state, ARMword va, - ARMword * data, ARMword datatype); - -ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value); -ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value); - - -/* jeff add 2010.9.26 for pxa270 cp6*/ -#define PXA270_ICMR 0x40D00004 -#define PXA270_ICPR 0x40D00010 -#define PXA270_ICLR 0x40D00008 -//chy 2005-09-19 for xscale pxa27x cp6 -unsigned -xscale_cp6_mrc (ARMul_State * state, unsigned type, ARMword instr, - ARMword * data) -{ - unsigned opcode_2 = BITS (5, 7); - unsigned CRm = BITS (0, 3); - unsigned reg = BITS (16, 19); - unsigned result; - - //printf("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,state->Reg[15], instr); - - switch (reg) { - case CR0_ICIP: { // cp 6 reg 0 - //printf("cp6_mrc cr0 ICIP \n"); - /* *data = (pxa270_io.icmr & pxa270_io.icpr) & ~pxa270_io.iclr; */ - /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/ - int icmr, icpr, iclr; - bus_read(32, PXA270_ICMR, (uint32_t*)&icmr); - bus_read(32, PXA270_ICPR, (uint32_t*)&icpr); - bus_read(32, PXA270_ICLR, (uint32_t*)&iclr); - *data = (icmr & icpr) & ~iclr; - } - break; - case CR1_ICMR: { // cp 6 reg 1 - //printf("cp6_mrc cr1 ICMR\n"); - /* *data = pxa270_io.icmr; */ - int icmr; - /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/ - bus_read(32, PXA270_ICMR, (uint32_t*)&icmr); - *data = icmr; - } - break; - default: - *data = 0; - printf ("SKYEYE:cp6_mrc unknown cp6 regs!!!!!!\n"); - printf ("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n", opcode_2, CRm, reg, state->Reg[15], instr); - break; - } - return 0; -} - -//chy 2005-09-19 end -//xscale cp13 ---------------------------------------------------- -unsigned -xscale_cp13_init (ARMul_State * state) -{ - //printf("SKYEYE: xscale_cp13_init: begin\n"); - return 0; -} - -unsigned -xscale_cp13_exit (ARMul_State * state) -{ - //printf("SKYEYE: xscale_cp13_exit: begin\n"); - return 0; -} - -unsigned -xscale_cp13_ldc (ARMul_State * state, unsigned type, ARMword instr, - ARMword data) -{ - printf ("SKYEYE: xscale_cp13_ldc: ERROR isn't existed,"); - SKYEYE_OUTREGS (stderr); - fprintf (stderr, "\n"); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} - -unsigned -xscale_cp13_stc (ARMul_State * state, unsigned type, ARMword instr, - ARMword * data) -{ - printf ("SKYEYE: xscale_cp13_stc: ERROR isn't existed,"); - SKYEYE_OUTREGS (stderr); - fprintf (stderr, "\n"); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} - -unsigned -xscale_cp13_mrc (ARMul_State * state, unsigned type, ARMword instr, - ARMword * data) -{ - printf ("SKYEYE: xscale_cp13_mrc: ERROR isn't existed,"); - SKYEYE_OUTREGS (stderr); - fprintf (stderr, "\n"); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} - -unsigned -xscale_cp13_mcr (ARMul_State * state, unsigned type, ARMword instr, - ARMword data) -{ - printf ("SKYEYE: xscale_cp13_mcr: ERROR isn't existed,"); - SKYEYE_OUTREGS (stderr); - fprintf (stderr, "\n"); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} - -unsigned -xscale_cp13_cdp (ARMul_State * state, unsigned type, ARMword instr) -{ - printf ("SKYEYE: xscale_cp13_cdp: ERROR isn't existed,"); - SKYEYE_OUTREGS (stderr); - fprintf (stderr, "\n"); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} - -unsigned -xscale_cp13_read_reg (ARMul_State * state, unsigned reg, ARMword * data) -{ - printf ("SKYEYE: xscale_cp13_read_reg: ERROR isn't existed,"); - SKYEYE_OUTREGS (stderr); - fprintf (stderr, "\n"); - return 0; - //exit(-1); -} - -unsigned -xscale_cp13_write_reg (ARMul_State * state, unsigned reg, ARMword data) -{ - printf ("SKYEYE: xscale_cp13_write_reg: ERROR isn't existed,"); - SKYEYE_OUTREGS (stderr); - fprintf (stderr, "\n"); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} - -//------------------------------------------------------------------ -//xscale cp14 ---------------------------------------------------- -unsigned -xscale_cp14_init (ARMul_State * state) -{ - //printf("SKYEYE: xscale_cp14_init: begin\n"); - pxa_cp14_regs.cclkcfg = 0; - pxa_cp14_regs.pwrmode = 0; - return 0; -} - -unsigned -xscale_cp14_exit (ARMul_State * state) -{ - //printf("SKYEYE: xscale_cp14_exit: begin\n"); - return 0; -} - -unsigned -xscale_cp14_ldc (ARMul_State * state, unsigned type, ARMword instr, - ARMword data) -{ - printf ("SKYEYE: xscale_cp14_ldc: ERROR isn't existed, reg15 0x%x\n", - state->Reg[15]); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} - -unsigned -xscale_cp14_stc (ARMul_State * state, unsigned type, ARMword instr, - ARMword * data) -{ - printf ("SKYEYE: xscale_cp14_stc: ERROR isn't existed, reg15 0x%x\n", - state->Reg[15]); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} - -unsigned -xscale_cp14_mrc (ARMul_State * state, unsigned type, ARMword instr, - ARMword * data) -{ - unsigned opcode_2 = BITS (5, 7); - unsigned CRm = BITS (0, 3); - unsigned reg = BITS (16, 19); - unsigned result; - - //printf("SKYEYE: xscale_cp14_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ - state->Reg[15], instr); - - switch (reg) { - case CCLKCFG: // cp 14 reg 6 - //printf("cp14_mrc cclkcfg \n"); - *data = pxa_cp14_regs.cclkcfg; - break; - case PWRMODE: // cp 14 reg 7 - //printf("cp14_mrc pwrmode \n"); - *data = pxa_cp14_regs.pwrmode; - break; - default: - *data = 0; - printf ("SKYEYE:cp14_mrc unknown cp14 regs!!!!!!\n"); - break; - } - return 0; -} -unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, ARMword instr, - ARMword data) -{ - unsigned opcode_2 = BITS (5, 7); - unsigned CRm = BITS (0, 3); - unsigned reg = BITS (16, 19); - unsigned result; - - //printf("SKYEYE: xscale_cp14_mcr:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ - state->Reg[15], instr); - - switch (reg) { - case CCLKCFG: // cp 14 reg 6 - //printf("cp14_mcr cclkcfg \n"); - pxa_cp14_regs.cclkcfg = data & 0xf; - break; - case PWRMODE: // cp 14 reg 7 - //printf("cp14_mcr pwrmode \n"); - pxa_cp14_regs.pwrmode = data & 0x3; - break; - default:printf ("SKYEYE: cp14_mcr unknown cp14 regs!!!!!!\n"); - break; - } - return 0; -} -unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, ARMword instr) -{ - printf ("SKYEYE: xscale_cp14_cdp: ERROR isn't existed, reg15 0x%x\n", - state->Reg[15]); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} -unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg, - ARMword * data) -{ - printf ("SKYEYE: xscale_cp14_read_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - return 0; //No matter return value, only for compiler. -} -unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg, - ARMword data) -{ - printf ("SKYEYE: xscale_cp14_write_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - - return 0; //No matter return value, only for compiler. -} - -//------------------------------------------------------------------ -//cp15 ------------------------------------- -unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, ARMword instr, - ARMword data) -{ - printf ("SKYEYE: xscale_cp15_ldc: ERROR isn't existed\n"); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - - return 0; //No matter return value, only for compiler. -} -unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, ARMword instr, - ARMword * data) -{ - printf ("SKYEYE: xscale_cp15_stc: ERROR isn't existed\n"); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - - return 0; //No matter return value, only for compiler. -} -unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, ARMword instr) -{ - printf ("SKYEYE: xscale_cp15_cdp: ERROR isn't existed\n"); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - - return 0; //No matter return value, only for compiler. -} -unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg, - ARMword * data) -{ -//chy 2003-09-03: for xsacle_cp15_cp_access_allowed - if (reg == 15) { - *data = state->mmu.copro_access; - //printf("SKYEYE: xscale_cp15_read_reg: reg 0x%x,data %x\n",reg,*data); - return 0; - } - printf ("SKYEYE: xscale_cp15_read_reg: reg 0x%x, ERROR isn't existed\n", reg); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - - return 0; //No matter return value, only for compiler. -} - -//chy 2003-09-03 used by macro CP_ACCESS_ALLOWED in armemu.h -unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, - unsigned cpnum) -{ - unsigned data; - - xscale_cp15_read_reg (state, reg, &data); - //printf("SKYEYE: cp15_cp_access_allowed data %x, cpnum %x, result %x\n", data, cpnum, (data & 1<<cpnum)); - if (data & 1 << cpnum) - return 1; - else - return 0; -} - -unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg, - ARMword value) -{ - switch (reg) { - case MMU_FAULT_STATUS: - //printf("SKYEYE:cp15_write_reg wrote FS val 0x%x \n",value); - state->mmu.fault_status = value & 0x6FF; - break; - case MMU_FAULT_ADDRESS: - //printf("SKYEYE:cp15_write_reg wrote FA val 0x%x \n",value); - state->mmu.fault_address = value; - break; - default: - printf ("SKYEYE: xscale_cp15_write_reg: reg 0x%x R15 %x ERROR isn't existed\n", reg, state->Reg[15]); - SKYEYE_OUTREGS (stderr); - // skyeye_exit (-1); - } - return 0; -} - -unsigned -xscale_cp15_init (ARMul_State * state) -{ - xscale_mmu_desc_t *desc; - cache_desc_t *c_desc; - - state->mmu.control = 0; - state->mmu.translation_table_base = 0xDEADC0DE; - state->mmu.domain_access_control = 0xDEADC0DE; - state->mmu.fault_status = 0; - state->mmu.fault_address = 0; - state->mmu.process_id = 0; - state->mmu.cache_type = 0xB1AA1AA; //0000 1011 0001 1010 1010 0001 1010 1010 - state->mmu.aux_control = 0; - - desc = &pxa_mmu_desc; - - if (mmu_tlb_init (I_TLB (), desc->i_tlb)) { - ERROR_LOG(ARM11, "i_tlb init %d\n", -1); - goto i_tlb_init_error; - } - - c_desc = &desc->i_cache; - if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way, - c_desc->set, c_desc->w_mode)) { - ERROR_LOG(ARM11, "i_cache init %d\n", -1); - goto i_cache_init_error; - } - - if (mmu_tlb_init (D_TLB (), desc->d_tlb)) { - ERROR_LOG(ARM11, "d_tlb init %d\n", -1); - goto d_tlb_init_error; - } - - c_desc = &desc->main_d_cache; - if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way, - c_desc->set, c_desc->w_mode)) { - ERROR_LOG(ARM11, "main_d_cache init %d\n", -1); - goto main_d_cache_init_error; - } - - c_desc = &desc->mini_d_cache; - if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way, - c_desc->set, c_desc->w_mode)) { - ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1); - goto mini_d_cache_init_error; - } - - if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) { - ERROR_LOG(ARM11, "wb init %d\n", -1); - goto wb_init_error; - } -#if 0 - if (mmu_rb_init (RB (), desc->rb)) { - ERROR_LOG(ARM11, "rb init %d\n", -1); - goto rb_init_error; - } -#endif - - return 0; -#if 0 - rb_init_error: - mmu_wb_exit (WB ()); -#endif - wb_init_error: - mmu_cache_exit (MINI_D_CACHE ()); - mini_d_cache_init_error: - mmu_cache_exit (MAIN_D_CACHE ()); - main_d_cache_init_error: - mmu_tlb_exit (D_TLB ()); - d_tlb_init_error: - mmu_cache_exit (I_CACHE ()); - i_cache_init_error: - mmu_tlb_exit (I_TLB ()); - i_tlb_init_error: - return -1; -} - -unsigned -xscale_cp15_exit (ARMul_State * state) -{ - //mmu_rb_exit(RB()); - mmu_wb_exit (WB ()); - mmu_cache_exit (MINI_D_CACHE ()); - mmu_cache_exit (MAIN_D_CACHE ()); - mmu_tlb_exit (D_TLB ()); - mmu_cache_exit (I_CACHE ()); - mmu_tlb_exit (I_TLB ()); - return 0; -}; - - -static fault_t - xscale_mmu_load_instr (ARMul_State * state, ARMword va, - ARMword * instr) -{ - fault_t fault; - tlb_entry_t *tlb; - cache_line_t *cache; - int c; //cache bit - ARMword pa; //physical addr - - static int debug_count = 0; //used for debug - - DEBUG_LOG(ARM11, "va = %x\n", va); - - va = mmu_pid_va_map (va); - if (MMU_Enabled) { - /*align check */ - if ((va & (INSN_SIZE - 1)) && MMU_Aligned) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } - else - va &= ~(INSN_SIZE - 1); - - /*translate tlb */ - fault = translate (state, va, I_TLB (), &tlb); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - return fault; - } - - /*check access */ - fault = check_access (state, va, tlb, 1); - if (fault) { - DEBUG_LOG(ARM11, "check_fault\n"); - return fault; - } - } - //chy 2003-09-02 for test, don't use cache ????? -#if 0 - /*search cache no matter MMU enabled/disabled */ - cache = mmu_cache_search (state, I_CACHE (), va); - if (cache) { - *instr = cache->data[va_cache_index (va, I_CACHE ())]; - return 0; - } -#endif - /*if MMU disabled or C flag is set alloc cache */ - if (MMU_Disabled) { - c = 1; - pa = va; - } - else { - c = tlb_c_flag (tlb); - pa = tlb_va_to_pa (tlb, va); - } - - //chy 2003-09-03 only read mem, don't use cache now,will change later ???? - //*instr = mem_read_word (state, pa); - bus_read(32, pa, instr); -#if 0 -//----------------------------------------------------------- - //chy 2003-09-02 for test???? - if (pa >= 0xa01c8000 && pa <= 0xa01c8020) { - printf ("SKYEYE:load_instr: pa %x, va %x,instr %x, R15 %x\n", - pa, va, *instr, state->Reg[15]); - } - -//---------------------------------------------------------------------- -#endif - return NO_FAULT; - - if (c) { - int index; - - debug_count++; - cache = mmu_cache_alloc (state, I_CACHE (), va, pa); - index = va_cache_index (va, I_CACHE ()); - *instr = cache->data[va_cache_index (va, I_CACHE ())]; - } - else - //*instr = mem_read_word (state, pa); - bus_read(32, pa, instr); - - return NO_FAULT; -}; - - - -static fault_t - xscale_mmu_read_byte (ARMul_State * state, ARMword virt_addr, - ARMword * data) -{ - //ARMword temp,offset; - fault_t fault; - fault = xscale_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); - return fault; -} - -static fault_t - xscale_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, - ARMword * data) -{ - //ARMword temp,offset; - fault_t fault; - fault = xscale_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); - return fault; -} - -static fault_t - xscale_mmu_read_word (ARMul_State * state, ARMword virt_addr, - ARMword * data) -{ - return xscale_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); -} - - - - -static fault_t - xscale_mmu_read (ARMul_State * state, ARMword va, ARMword * data, - ARMword datatype) -{ - fault_t fault; -// rb_entry_t *rb; - tlb_entry_t *tlb; - cache_line_t *cache; - ARMword pa, real_va, temp, offset; - //chy 2003-09-02 for test ???? - static unsigned chyst1 = 0, chyst2 = 0; - - DEBUG_LOG(ARM11, "va = %x\n", va); - - va = mmu_pid_va_map (va); - real_va = va; - /*if MMU disabled, memory_read */ - if (MMU_Disabled) { - //*data = mem_read_word(state, va); - if (datatype == ARM_BYTE_TYPE) - //*data = mem_read_byte (state, va); - bus_read(8, va, data); - else if (datatype == ARM_HALFWORD_TYPE) - //*data = mem_read_halfword (state, va); - bus_read(16, va, data); - else if (datatype == ARM_WORD_TYPE) - //*data = mem_read_word (state, va); - bus_read(32, va, data); - else { - printf ("SKYEYE:1 xscale_mmu_read error: unknown data type %d\n", datatype); - // skyeye_exit (-1); - } - - return NO_FAULT; - } - - /*align check */ - if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || - ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } // else - - va &= ~(WORD_SIZE - 1); - - /*translate va to tlb */ - fault = translate (state, va, D_TLB (), &tlb); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - return fault; - } - /*check access permission */ - fault = check_access (state, va, tlb, 1); - if (fault) - return fault; - -#if 0 -//------------------------------------------------ -//chy 2003-09-02 for test only ,should commit ???? - if (datatype == ARM_WORD_TYPE) { - if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { - pa = tlb_va_to_pa (tlb, va); - *data = mem_read_word (state, pa); - chyst1++; - printf ("**SKYEYE:mmu_read word %d: pa %x, va %x, data %x, R15 %x\n", chyst1, pa, real_va, *data, state->Reg[15]); - /* - cache==mmu_cache_search(state,MAIN_D_CACHE(),va); - if(cache){ - *data = cache->data[va_cache_index(va, MAIN_D_CACHE())]; - printf("cached data %x\n",*data); - }else printf("no cached data\n"); - */ - } - } -//------------------------------------------------- -#endif -#if 0 - /*search in read buffer */ - rb = mmu_rb_search (RB (), va); - if (rb) { - if (rb->fault) - return rb->fault; - *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT]; - goto datatrans; - //return 0; - }; -#endif - - /*2004-07-19 chy: add support of xscale MMU CacheDisabled option */ - if (MMU_CacheDisabled) { - //if(1){ can be used to test cache error - /*get phy_addr */ - pa = tlb_va_to_pa (tlb, real_va); - if (datatype == ARM_BYTE_TYPE) - //*data = mem_read_byte (state, pa); - bus_read(8, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - //*data = mem_read_halfword (state, pa); - bus_read(16, pa, data); - else if (datatype == ARM_WORD_TYPE) - //*data = mem_read_word (state, pa); - bus_read(32, pa, data); - else { - printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_read error: unknown data type %d\n", datatype); - // skyeye_exit (-1); - } - return NO_FAULT; - } - - - /*search main cache */ - cache = mmu_cache_search (state, MAIN_D_CACHE (), va); - if (cache) { - *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())]; -#if 0 -//------------------------------------------------------------------------ -//chy 2003-09-02 for test only ,should commit ???? - if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { - pa = tlb_va_to_pa (tlb, va); - chyst2++; - printf ("**SKYEYE:mmu_read wordk:cache %d: pa %x, va %x, data %x, R15 %x\n", chyst2, pa, real_va, *data, state->Reg[15]); - } -//------------------------------------------------------------------- -#endif - goto datatrans; - //return 0; - } - //chy 2003-08-24, now maybe we don't need minidcache ???? -#if 0 - /*search mini cache */ - cache = mmu_cache_search (state, MINI_D_CACHE (), va); - if (cache) { - *data = cache->data[va_cache_index (va, MINI_D_CACHE ())]; - goto datatrans; - //return 0; - } -#endif - /*get phy_addr */ - pa = tlb_va_to_pa (tlb, va); - //chy 2003-08-24 , in xscale it means what ????? -#if 0 - if ((pa >= 0xe0000000) && (pa < 0xe8000000)) { - - if (tlb_c_flag (tlb)) { - if (tlb_b_flag (tlb)) { - mmu_cache_soft_flush (state, MAIN_D_CACHE (), - pa); - } - else { - mmu_cache_soft_flush (state, MINI_D_CACHE (), - pa); - } - } - return 0; - } -#endif - //chy 2003-08-24, check phy addr - //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address - /* - if(pa >= 0xb0000000){ - printf("SKYEYE:xscale_mmu_read: phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]); - return 0; - } - */ - - //chy 2003-08-24, now maybe we don't need wb ???? -#if 0 - /*if Buffer, drain Write Buffer first */ - if (tlb_b_flag (tlb)) - mmu_wb_drain_all (state, WB ()); -#endif - /*alloc cache or mem_read */ - if (tlb_c_flag (tlb) && MMU_DCacheEnabled) { - cache_s *cache_t; - - if (tlb_b_flag (tlb)) - cache_t = MAIN_D_CACHE (); - else - cache_t = MINI_D_CACHE (); - cache = mmu_cache_alloc (state, cache_t, va, pa); - *data = cache->data[va_cache_index (va, cache_t)]; - } - else { - //*data = mem_read_word(state, pa); - if (datatype == ARM_BYTE_TYPE) - //*data = mem_read_byte (state, pa | (real_va & 3)); - bus_read(8, pa | (real_va & 3), data); - else if (datatype == ARM_HALFWORD_TYPE) - //*data = mem_read_halfword (state, pa | (real_va & 2)); - bus_read(16, pa | (real_va & 2), data); - else if (datatype == ARM_WORD_TYPE) - //*data = mem_read_word (state, pa); - bus_read(32, pa, data); - else { - printf ("SKYEYE:2 xscale_mmu_read error: unknown data type %d\n", datatype); - // skyeye_exit (-1); - } - return NO_FAULT; - } - - - datatrans: - if (datatype == ARM_HALFWORD_TYPE) { - temp = *data; - offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ - *data = (temp >> offset) & 0xffff; - } - else if (datatype == ARM_BYTE_TYPE) { - temp = *data; - offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ - *data = (temp >> offset & 0xffL); - } - end: - return NO_FAULT; -} - - -static fault_t - xscale_mmu_write_byte (ARMul_State * state, ARMword virt_addr, - ARMword data) -{ - return xscale_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); -} - -static fault_t - xscale_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, - ARMword data) -{ - return xscale_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); -} - -static fault_t - xscale_mmu_write_word (ARMul_State * state, ARMword virt_addr, - ARMword data) -{ - return xscale_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); -} - - - -static fault_t - xscale_mmu_write (ARMul_State * state, ARMword va, ARMword data, - ARMword datatype) -{ - tlb_entry_t *tlb; - cache_line_t *cache; - cache_s *cache_t; - int b; - ARMword pa, real_va, temp, offset; - fault_t fault; - - ARMword index; -//chy 2003-09-02 for test ???? -// static unsigned chyst1=0,chyst2=0; - - DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); - va = mmu_pid_va_map (va); - real_va = va; - - if (MMU_Disabled) { - //mem_write_word(state, va, data); - if (datatype == ARM_BYTE_TYPE) - //mem_write_byte (state, va, data); - bus_write(8, va, data); - else if (datatype == ARM_HALFWORD_TYPE) - //mem_write_halfword (state, va, data); - bus_write(16, va, data); - else if (datatype == ARM_WORD_TYPE) - //mem_write_word (state, va, data); - bus_write(32, va, data); - else { - printf ("SKYEYE:1 xscale_mmu_write error: unknown data type %d\n", datatype); - // skyeye_exit (-1); - } - - return NO_FAULT; - } - /*align check */ - if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || - ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } //else - va &= ~(WORD_SIZE - 1); - /*tlb translate */ - fault = translate (state, va, D_TLB (), &tlb); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - return fault; - } - /*tlb check access */ - fault = check_access (state, va, tlb, 0); - if (fault) { - DEBUG_LOG(ARM11, "check_access\n"); - return fault; - } - - /*2004-07-19 chy: add support for xscale MMU_CacheDisabled */ - if (MMU_CacheDisabled) { - //if(1){ can be used to test the cache error - /*get phy_addr */ - pa = tlb_va_to_pa (tlb, real_va); - if (datatype == ARM_BYTE_TYPE) - //mem_write_byte (state, pa, data); - bus_write(8, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - //mem_write_halfword (state, pa, data); - bus_write(16, pa, data); - else if (datatype == ARM_WORD_TYPE) - //mem_write_word (state, pa, data); - bus_write(32, pa , data); - else { - printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_write error: unknown data type %d\n", datatype); - // skyeye_exit (-1); - } - - return NO_FAULT; - } - - /*search main cache */ - b = tlb_b_flag (tlb); - pa = tlb_va_to_pa (tlb, va); - cache = mmu_cache_search (state, MAIN_D_CACHE (), va); - if (cache) { - cache_t = MAIN_D_CACHE (); - goto has_cache; - } - //chy 2003-08-24, now maybe we don't need minidcache ???? -#if 0 - /*search mini cache */ - cache = mmu_cache_search (state, MINI_D_CACHE (), va); - if (cache) { - cache_t = MINI_D_CACHE (); - goto has_cache; - } -#endif - b = tlb_b_flag (tlb); - pa = tlb_va_to_pa (tlb, va); - //chy 2003-08-24, check phy addr 0xa0000000, size 0x04000000 - //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address - /* - if(pa >= 0xb0000000){ - printf("SKYEYE:xscale_mmu_write phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]); - return 0; - } - */ - - //chy 2003-08-24, now maybe we don't need WB ???? -#if 0 - if (b) { - if (MMU_WBEnabled) { - if (datatype == ARM_WORD_TYPE) - mmu_wb_write_bytes (state, WB (), pa, &data, - 4); - else if (datatype == ARM_HALFWORD_TYPE) - mmu_wb_write_bytes (state, WB (), - (pa | (real_va & 2)), - &data, 2); - else if (datatype == ARM_BYTE_TYPE) - mmu_wb_write_bytes (state, WB (), - (pa | (real_va & 3)), - &data, 1); - - } - else { - if (datatype == ARM_WORD_TYPE) - mem_write_word (state, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - mem_write_halfword (state, - (pa | (real_va & 2)), - data); - else if (datatype == ARM_BYTE_TYPE) - mem_write_byte (state, (pa | (real_va & 3)), - data); - } - } - else { - - mmu_wb_drain_all (state, WB ()); - - if (datatype == ARM_WORD_TYPE) - mem_write_word (state, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - mem_write_halfword (state, (pa | (real_va & 2)), - data); - else if (datatype == ARM_BYTE_TYPE) - mem_write_byte (state, (pa | (real_va & 3)), data); - } -#endif - //chy 2003-08-24, just write phy addr - if (datatype == ARM_WORD_TYPE) - //mem_write_word (state, pa, data); - bus_write(32, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - //mem_write_halfword (state, (pa | (real_va & 2)), data); - bus_write(16, pa | (real_va & 2), data); - else if (datatype == ARM_BYTE_TYPE) - //mem_write_byte (state, (pa | (real_va & 3)), data); - bus_write(8, (pa | (real_va & 3)), data); -#if 0 -//------------------------------------------------------------- -//chy 2003-09-02 for test ???? - if (datatype == ARM_WORD_TYPE) { - if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { - printf ("**SKYEYE:mmu_write word: pa %x, va %x, data %x, R15 %x \n", pa, real_va, data, state->Reg[15]); - } - } -//-------------------------------------------------------------- -#endif - return NO_FAULT; - - has_cache: - index = va_cache_index (va, cache_t); - //cache->data[index] = data; - - if (datatype == ARM_WORD_TYPE) - cache->data[index] = data; - else if (datatype == ARM_HALFWORD_TYPE) { - temp = cache->data[index]; - offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ - cache->data[index] = - (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << - offset); - } - else if (datatype == ARM_BYTE_TYPE) { - temp = cache->data[index]; - offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ - cache->data[index] = - (temp & ~(0xffL << offset)) | ((data & 0xffL) << - offset); - } - - if (index < (cache_t->width >> (WORD_SHT + 1))) - cache->tag |= TAG_FIRST_HALF_DIRTY; - else - cache->tag |= TAG_LAST_HALF_DIRTY; -//------------------------------------------------------------- -//chy 2003-09-03 be sure the changed value will be in memory as soon as possible, so I cache can get the newest value -#if 0 - { - if (datatype == ARM_WORD_TYPE) - mem_write_word (state, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - mem_write_halfword (state, (pa | (real_va & 2)), - data); - else if (datatype == ARM_BYTE_TYPE) - mem_write_byte (state, (pa | (real_va & 3)), data); - } -#endif -#if 0 -//chy 2003-09-02 for test ???? - if (datatype == ARM_WORD_TYPE) { - if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { - printf ("**SKYEYE:mmu_write word:cache: pa %x, va %x, data %x, R15 %x\n", pa, real_va, data, state->Reg[15]); - } - } -//------------------------------------------------------------- -#endif - if (datatype == ARM_WORD_TYPE) - //mem_write_word (state, pa, data); - bus_write(32, pa, data); - else if (datatype == ARM_HALFWORD_TYPE) - //mem_write_halfword (state, (pa | (real_va & 2)), data); - bus_write(16, pa | (real_va & 2), data); - else if (datatype == ARM_BYTE_TYPE) - //mem_write_byte (state, (pa | (real_va & 3)), data); - bus_write(8, (pa | (real_va & 3)), data); - return NO_FAULT; -} - -ARMword xscale_cp15_mrc (ARMul_State * state, - unsigned type, ARMword instr, ARMword * value) -{ - return xscale_mmu_mrc (state, instr, value); -} - -ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) -{ - ARMword data; - unsigned opcode_2 = BITS (5, 7); - unsigned CRm = BITS (0, 3); - unsigned reg = BITS (16, 19); - unsigned result; - mmu_regnum_t creg = (mmu_regnum_t)reg; - -/* - printf("SKYEYE: xscale_cp15_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ - state->Reg[15], instr); -*/ - switch (creg) { - case MMU_ID: //XSCALE_CP15 - //printf("mmu_mrc read ID \n"); - data = (opcode_2 ? state->mmu.cache_type : state->cpu-> - cpu_val); - break; - case MMU_CONTROL: //XSCALE_CP15_AUX_CONTROL - //printf("mmu_mrc read CONTROL \n"); - data = (opcode_2 ? state->mmu.aux_control : state->mmu. - control); - break; - case MMU_TRANSLATION_TABLE_BASE: - //printf("mmu_mrc read TTB \n"); - data = state->mmu.translation_table_base; - break; - case MMU_DOMAIN_ACCESS_CONTROL: - //printf("mmu_mrc read DACR \n"); - data = state->mmu.domain_access_control; - break; - case MMU_FAULT_STATUS: - //printf("mmu_mrc read FSR \n"); - data = state->mmu.fault_status; - break; - case MMU_FAULT_ADDRESS: - //printf("mmu_mrc read FAR \n"); - data = state->mmu.fault_address; - break; - case MMU_PID: - //printf("mmu_mrc read PID \n"); - data = state->mmu.process_id; - case XSCALE_CP15_COPRO_ACCESS: - //printf("xscale cp15 read coprocessor access\n"); - data = state->mmu.copro_access; - break; - default: - data = 0; - printf ("SKYEYE: xscale_cp15_mrc read UNKNOWN - reg %d, pc 0x%x\n", creg, state->Reg[15]); - // skyeye_exit (-1); - break; - } - *value = data; - //printf("SKYEYE: xscale_cp15_mrc:end value 0x%x\n",data); - return ARMul_DONE; -} - -void xscale_cp15_cache_ops (ARMul_State * state, ARMword instr, ARMword value) -{ -//chy: 2003-08-24 now, the BTB isn't simualted ....???? - - unsigned CRm, OPC_2; - - CRm = BITS (0, 3); - OPC_2 = BITS (5, 7); - //err_msg("SKYEYE: xscale cp15_cache_ops:OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm,state->Reg[15]); - - if (OPC_2 == 0 && CRm == 7) { - mmu_cache_invalidate_all (state, I_CACHE ()); - mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); - return; - } - - if (OPC_2 == 0 && CRm == 5) { - mmu_cache_invalidate_all (state, I_CACHE ()); - return; - } - if (OPC_2 == 1 && CRm == 5) { - mmu_cache_invalidate (state, I_CACHE (), value); - return; - } - - if (OPC_2 == 0 && CRm == 6) { - mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); - return; - } - - if (OPC_2 == 1 && CRm == 6) { - mmu_cache_invalidate (state, MAIN_D_CACHE (), value); - return; - } - - if (OPC_2 == 1 && CRm == 0xa) { - mmu_cache_clean (state, MAIN_D_CACHE (), value); - return; - } - - if (OPC_2 == 4 && CRm == 0xa) { - mmu_wb_drain_all (state, WB ()); - return; - } - - if (OPC_2 == 6 && CRm == 5) { - //chy 2004-07-19 shoud fix in the future????!!!! - //printf("SKYEYE: xscale_cp15_cache_ops:invalidate BTB CANT!!!!!!!!!!\n"); - //exit(-1); - return; - } - - if (OPC_2 == 5 && CRm == 2) { - //printf("SKYEYE: cp15_c_o: A L in D C, value %x, reg15 %x\n",value, state->Reg[15]); - //exit(-1); - //chy 2003-09-01 for test - mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); - return; - } - - ERROR_LOG(ARM11, "SKYEYE: xscale cp15_cache_ops:Unknown OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm, state->Reg[15]); - // skyeye_exit (-1); -} - -static void - xscale_cp15_tlb_ops (ARMul_State * state, ARMword instr, - ARMword value) -{ - int CRm, OPC_2; - - CRm = BITS (0, 3); - OPC_2 = BITS (5, 7); - - - //err_msg("SKYEYE:xscale_cp15_tlb_ops:OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm,state->Reg[15]); - if (OPC_2 == 0 && CRm == 0x7) { - mmu_tlb_invalidate_all (state, I_TLB ()); - mmu_tlb_invalidate_all (state, D_TLB ()); - return; - } - - if (OPC_2 == 0 && CRm == 0x5) { - mmu_tlb_invalidate_all (state, I_TLB ()); - return; - } - - if (OPC_2 == 1 && CRm == 0x5) { - mmu_tlb_invalidate_entry (state, I_TLB (), value); - return; - } - - if (OPC_2 == 0 && CRm == 0x6) { - mmu_tlb_invalidate_all (state, D_TLB ()); - return; - } - - if (OPC_2 == 1 && CRm == 0x6) { - mmu_tlb_invalidate_entry (state, D_TLB (), value); - return; - } - - ERROR_LOG(ARM11, "SKYEYE:xscale_cp15_tlb_ops:Unknow OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm, state->Reg[15]); - // skyeye_exit (-1); -} - - -ARMword xscale_cp15_mcr (ARMul_State * state, - unsigned type, ARMword instr, ARMword value) -{ - return xscale_mmu_mcr (state, instr, value); -} - -ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) -{ - ARMword data; - unsigned opcode_2 = BITS (5, 7); - unsigned CRm = BITS (0, 3); - unsigned reg = BITS (16, 19); - unsigned result; - mmu_regnum_t creg = (mmu_regnum_t)reg; - - //printf("SKYEYE: xscale_cp15_mcr: opcode_2 0x%x, CRm 0x%x, reg ox%x, value 0x%x, reg[15] 0x%x, instr 0x%x\n",opcode_2,CRm,reg, value, state->Reg[15], instr); - - switch (creg) { - case MMU_CONTROL: - //printf("mmu_mcr wrote CONTROL val 0x%x \n",value); - state->mmu.control = - (opcode_2 ? (value & 0x33) : (value & 0x3FFF)); - break; - case MMU_TRANSLATION_TABLE_BASE: - //printf("mmu_mcr wrote TTB val 0x%x \n",value); - state->mmu.translation_table_base = value & 0xFFFFC000; - break; - case MMU_DOMAIN_ACCESS_CONTROL: - //printf("mmu_mcr wrote DACR val 0x%x \n",value); - state->mmu.domain_access_control = value; - break; - - case MMU_FAULT_STATUS: - //printf("mmu_mcr wrote FS val 0x%x \n",value); - state->mmu.fault_status = value & 0x6FF; - break; - case MMU_FAULT_ADDRESS: - //printf("mmu_mcr wrote FA val 0x%x \n",value); - state->mmu.fault_address = value; - break; - - case MMU_CACHE_OPS: -// printf("mmu_mcr wrote CO val 0x%x \n",value); - xscale_cp15_cache_ops (state, instr, value); - break; - case MMU_TLB_OPS: - //printf("mmu_mcr wrote TO val 0x%x \n",value); - xscale_cp15_tlb_ops (state, instr, value); - break; - case MMU_PID: - //printf("mmu_mcr wrote PID val 0x%x \n",value); - state->mmu.process_id = value & 0xfe000000; - break; - case XSCALE_CP15_COPRO_ACCESS: - //printf("xscale cp15 write coprocessor access val 0x %x\n",value); - state->mmu.copro_access = value & 0x3ff; - break; - - default: - printf ("SKYEYE: xscale_cp15_mcr wrote UNKNOWN - reg %d, reg15 0x%x\n", creg, state->Reg[15]); - break; - } - //printf("SKYEYE: xscale_cp15_mcr wrote val 0x%x\n", value); - return 0; -} - -//teawater add for arm2x86 2005.06.24------------------------------------------- -static int xscale_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, - ARMword * phys_addr) -{ - fault_t fault; - tlb_entry_t *tlb; - - virt_addr = mmu_pid_va_map (virt_addr); - if (MMU_Enabled) { - - /*align check */ - if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { - DEBUG_LOG(ARM11, "align\n"); - return ALIGNMENT_FAULT; - } - else - virt_addr &= ~(WORD_SIZE - 1); - - /*translate tlb */ - fault = translate (state, virt_addr, I_TLB (), &tlb); - if (fault) { - DEBUG_LOG(ARM11, "translate\n"); - return fault; - } - - /*check access */ - fault = check_access (state, virt_addr, tlb, 1); - if (fault) { - DEBUG_LOG(ARM11, "check_fault\n"); - return fault; - } - } - - if (MMU_Disabled) { - *phys_addr = virt_addr; - } - else { - *phys_addr = tlb_va_to_pa (tlb, virt_addr); - } - - return (0); -} - -//AJ2D-------------------------------------------------------------------------- - -/*xscale mmu_ops_t*/ -//mmu_ops_t xscale_mmu_ops = { -// xscale_cp15_init, -// xscale_cp15_exit, -// xscale_mmu_read_byte, -// xscale_mmu_write_byte, -// xscale_mmu_read_halfword, -// xscale_mmu_write_halfword, -// xscale_mmu_read_word, -// xscale_mmu_write_word, -// xscale_mmu_load_instr, xscale_mmu_mcr, xscale_mmu_mrc, -////teawater add for arm2x86 2005.06.24------------------------------------------- -// xscale_mmu_v2p_dbct, -////AJ2D-------------------------------------------------------------------------- -//}; diff --git a/src/core/arm/interpreter/thumbemu.cpp b/src/core/arm/interpreter/thumbemu.cpp index 032d84b65..f7f11f714 100644 --- a/src/core/arm/interpreter/thumbemu.cpp +++ b/src/core/arm/interpreter/thumbemu.cpp @@ -19,7 +19,7 @@ instruction into its corresponding ARM instruction, and using the existing ARM simulator. */ -#include "skyeye_defs.h" +#include "core/arm/skyeye_common/skyeye_defs.h" #ifndef MODET /* required for the Thumb instruction support */ #if 1 @@ -29,9 +29,9 @@ existing ARM simulator. */ #endif #endif -#include "armdefs.h" -#include "armemu.h" -#include "armos.h" +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/armemu.h" +#include "core/arm/skyeye_common/armos.h" /* Decode a 16bit Thumb instruction. The instruction is in the low diff --git a/src/core/arm/interpreter/vfp/vfp.cpp b/src/core/arm/interpreter/vfp/vfp.cpp deleted file mode 100644 index eea5e24a9..000000000 --- a/src/core/arm/interpreter/vfp/vfp.cpp +++ /dev/null @@ -1,357 +0,0 @@ -/* - armvfp.c - ARM VFPv3 emulation unit - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to <skyeye-developer@lists.gro.clinux.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* Note: this file handles interface with arm core and vfp registers */ - -/* Opens debug for classic interpreter only */ -//#define DEBUG - -#include "common/common.h" - -#include "core/arm/interpreter/armdefs.h" -#include "core/arm/interpreter/vfp/vfp.h" - -//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */ - -unsigned -VFPInit (ARMul_State *state) -{ - state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | - VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; - state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0; - state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0; - - //persistent_state = state; - /* Reset only specify VFP_FPEXC_EN = '0' */ - - return No_exp; -} - -unsigned -VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value) -{ - /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (21, 23); - int Rt = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); - - /* TODO check access permission */ - - /* CRn/opc1 CRm/opc2 */ - - if (CoProc == 10 || CoProc == 11) - { - #define VFP_MRC_TRANS - #include "core/arm/interpreter/vfp/vfpinstr.cpp" - #undef VFP_MRC_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", - instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); - - return ARMul_CANT; -} - -unsigned -VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value) -{ - /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (21, 23); - int Rt = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); - - /* TODO check access permission */ - - /* CRn/opc1 CRm/opc2 */ - if (CoProc == 10 || CoProc == 11) - { - #define VFP_MCR_TRANS - #include "core/arm/interpreter/vfp/vfpinstr.cpp" - #undef VFP_MCR_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", - instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); - - return ARMul_CANT; -} - -unsigned -VFPMRRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value1, ARMword * value2) -{ - /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (4, 7); - int Rt = BITS (12, 15); - int Rt2 = BITS (16, 19); - int CRm = BITS (0, 3); - - if (CoProc == 10 || CoProc == 11) - { - #define VFP_MRRC_TRANS - #include "core/arm/interpreter/vfp/vfpinstr.cpp" - #undef VFP_MRRC_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", - instr, CoProc, OPC_1, Rt, Rt2, CRm); - - return ARMul_CANT; -} - -unsigned -VFPMCRR (ARMul_State * state, unsigned type, ARMword instr, ARMword value1, ARMword value2) -{ - /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (4, 7); - int Rt = BITS (12, 15); - int Rt2 = BITS (16, 19); - int CRm = BITS (0, 3); - - /* TODO check access permission */ - - /* CRn/opc1 CRm/opc2 */ - - if (CoProc == 11 || CoProc == 10) - { - #define VFP_MCRR_TRANS - #include "core/arm/interpreter/vfp/vfpinstr.cpp" - #undef VFP_MCRR_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", - instr, CoProc, OPC_1, Rt, Rt2, CRm); - - return ARMul_CANT; -} - -unsigned -VFPSTC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value) -{ - /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int CRd = BITS (12, 15); - int Rn = BITS (16, 19); - int imm8 = BITS (0, 7); - int P = BIT(24); - int U = BIT(23); - int D = BIT(22); - int W = BIT(21); - - /* TODO check access permission */ - - /* VSTM */ - if ( (P|U|D|W) == 0 ) - { - DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1); - } - if (CoProc == 10 || CoProc == 11) - { - #if 1 - if (P == 0 && U == 0 && W == 0) - { - DEBUG_LOG(ARM11, "VSTM Related encodings\n"); exit(-1); - } - if (P == U && W == 1) - { - DEBUG_LOG(ARM11, "UNDEFINED\n"); exit(-1); - } - #endif - - #define VFP_STC_TRANS - #include "core/arm/interpreter/vfp/vfpinstr.cpp" - #undef VFP_STC_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", - instr, CoProc, CRd, Rn, imm8, P, U, D, W); - - return ARMul_CANT; -} - -unsigned -VFPLDC (ARMul_State * state, unsigned type, ARMword instr, ARMword value) -{ - /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int CRd = BITS (12, 15); - int Rn = BITS (16, 19); - int imm8 = BITS (0, 7); - int P = BIT(24); - int U = BIT(23); - int D = BIT(22); - int W = BIT(21); - - /* TODO check access permission */ - - if ( (P|U|D|W) == 0 ) - { - DEBUG_LOG(ARM11, "In %s, UNDEFINED\n", __FUNCTION__); exit(-1); - } - if (CoProc == 10 || CoProc == 11) - { - #define VFP_LDC_TRANS - #include "core/arm/interpreter/vfp/vfpinstr.cpp" - #undef VFP_LDC_TRANS - } - DEBUG_LOG(ARM11, "Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", - instr, CoProc, CRd, Rn, imm8, P, U, D, W); - - return ARMul_CANT; -} - -unsigned -VFPCDP (ARMul_State * state, unsigned type, ARMword instr) -{ - /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ - int CoProc = BITS (8, 11); /* 10 or 11 */ - int OPC_1 = BITS (20, 23); - int CRd = BITS (12, 15); - int CRn = BITS (16, 19); - int CRm = BITS (0, 3); - int OPC_2 = BITS (5, 7); - - /* TODO check access permission */ - - /* CRn/opc1 CRm/opc2 */ - - if (CoProc == 10 || CoProc == 11) - { - #define VFP_CDP_TRANS - #include "core/arm/interpreter/vfp/vfpinstr.cpp" - #undef VFP_CDP_TRANS - - int exceptions = 0; - if (CoProc == 10) - exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); - else - exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); - - vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); - - return ARMul_DONE; - } - DEBUG_LOG(ARM11, "Can't identify %x\n", instr); - return ARMul_CANT; -} - - -/* ----------- MRC ------------ */ -#define VFP_MRC_IMPL -#include "core/arm/interpreter/vfp/vfpinstr.cpp" -#undef VFP_MRC_IMPL - -#define VFP_MRRC_IMPL -#include "core/arm/interpreter/vfp/vfpinstr.cpp" -#undef VFP_MRRC_IMPL - - -/* ----------- MCR ------------ */ -#define VFP_MCR_IMPL -#include "core/arm/interpreter/vfp/vfpinstr.cpp" -#undef VFP_MCR_IMPL - -#define VFP_MCRR_IMPL -#include "core/arm/interpreter/vfp/vfpinstr.cpp" -#undef VFP_MCRR_IMPL - -/* Memory operation are not inlined, as old Interpreter and Fast interpreter - don't have the same memory operation interface. - Old interpreter framework does one access to coprocessor per data, and - handles already data write, as well as address computation, - which is not the case for Fast interpreter. Therefore, implementation - of vfp instructions in old interpreter and fast interpreter are separate. */ - -/* ----------- STC ------------ */ -#define VFP_STC_IMPL -#include "core/arm/interpreter/vfp/vfpinstr.cpp" -#undef VFP_STC_IMPL - - -/* ----------- LDC ------------ */ -#define VFP_LDC_IMPL -#include "core/arm/interpreter/vfp/vfpinstr.cpp" -#undef VFP_LDC_IMPL - - -/* ----------- CDP ------------ */ -#define VFP_CDP_IMPL -#include "core/arm/interpreter/vfp/vfpinstr.cpp" -#undef VFP_CDP_IMPL - -/* Miscellaneous functions */ -int32_t vfp_get_float(arm_core_t* state, unsigned int reg) -{ - DBG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]); - return state->ExtReg[reg]; -} - -void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg) -{ - DBG("VFP put float: s%d <= [%08x]\n", reg, val); - state->ExtReg[reg] = val; -} - -uint64_t vfp_get_double(arm_core_t* state, unsigned int reg) -{ - uint64_t result; - result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; - DBG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result); - return result; -} - -void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg) -{ - DBG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff)); - state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff); - state->ExtReg[reg*2+1] = (uint32_t) (val>>32); -} - - - -/* - * Process bitmask of exception conditions. (from vfpmodule.c) - */ -void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) -{ - int si_code = 0; - - vfpdebug("VFP: raising exceptions %08x\n", exceptions); - - if (exceptions == VFP_EXCEPTION_ERROR) { - DEBUG_LOG(ARM11, "unhandled bounce %x\n", inst); - exit(-1); - return; - } - - /* - * If any of the status flags are set, update the FPSCR. - * Comparison instructions always return at least one of - * these flags set. - */ - if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) - fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); - - fpscr |= exceptions; - - state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr; -} diff --git a/src/core/arm/interpreter/vfp/vfpdouble.cpp b/src/core/arm/interpreter/vfp/vfpdouble.cpp deleted file mode 100644 index 5ae99b88a..000000000 --- a/src/core/arm/interpreter/vfp/vfpdouble.cpp +++ /dev/null @@ -1,1263 +0,0 @@ -/* - vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to <skyeye-developer@lists.gro.clinux.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * This code is derived in part from : - * - Android kernel - * - John R. Housers softfloat library, which - * carries the following notice: - * - * =========================================================================== - * This C source file is part of the SoftFloat IEC/IEEE Floating-point - * Arithmetic Package, Release 2. - * - * Written by John R. Hauser. This work was made possible in part by the - * International Computer Science Institute, located at Suite 600, 1947 Center - * Street, Berkeley, California 94704. Funding was partially provided by the - * National Science Foundation under grant MIP-9311980. The original version - * of this code was written as part of a project to build a fixed-point vector - * processor in collaboration with the University of California at Berkeley, - * overseen by Profs. Nelson Morgan and John Wawrzynek. More information - * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ - * arithmetic/softfloat.html'. - * - * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort - * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT - * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO - * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY - * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - * - * Derivative works are acceptable, even for commercial purposes, so long as - * (1) they include prominent notice that the work is derivative, and (2) they - * include prominent notice akin to these three paragraphs for those parts of - * this code that are retained. - * =========================================================================== - */ - -#include "core/arm/interpreter/vfp/vfp.h" -#include "core/arm/interpreter/vfp/vfp_helper.h" -#include "core/arm/interpreter/vfp/asm_vfp.h" - -static struct vfp_double vfp_double_default_qnan = { - //.exponent = 2047, - //.sign = 0, - //.significand = VFP_DOUBLE_SIGNIFICAND_QNAN, -}; - -static void vfp_double_dump(const char *str, struct vfp_double *d) -{ - pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n", - str, d->sign != 0, d->exponent, d->significand); -} - -static void vfp_double_normalise_denormal(struct vfp_double *vd) -{ - int bits = 31 - vfp_fls(vd->significand >> 32); - if (bits == 31) - bits = 63 - vfp_fls(vd->significand); - - vfp_double_dump("normalise_denormal: in", vd); - - if (bits) { - vd->exponent -= bits - 1; - vd->significand <<= bits; - } - - vfp_double_dump("normalise_denormal: out", vd); -} - -u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) -{ - u64 significand, incr; - int exponent, shift, underflow; - u32 rmode; - - vfp_double_dump("pack: in", vd); - - /* - * Infinities and NaNs are a special case. - */ - if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) - goto pack; - - /* - * Special-case zero. - */ - if (vd->significand == 0) { - vd->exponent = 0; - goto pack; - } - - exponent = vd->exponent; - significand = vd->significand; - - shift = 32 - vfp_fls(significand >> 32); - if (shift == 32) - shift = 64 - vfp_fls(significand); - if (shift) { - exponent -= shift; - significand <<= shift; - } - -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: normalised", vd); -#endif - - /* - * Tiny number? - */ - underflow = exponent < 0; - if (underflow) { - significand = vfp_shiftright64jamming(significand, -exponent); - exponent = 0; -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: tiny number", vd); -#endif - if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) - underflow = 0; - } - - /* - * Select rounding increment. - */ - incr = 0; - rmode = fpscr & FPSCR_RMODE_MASK; - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 1ULL << VFP_DOUBLE_LOW_BITS; - if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) - incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; - - pr_debug("VFP: rounding increment = 0x%08llx\n", incr); - - /* - * Is our rounding going to overflow? - */ - if ((significand + incr) < significand) { - exponent += 1; - significand = (significand >> 1) | (significand & 1); - incr >>= 1; -#if 1 - vd->exponent = exponent; - vd->significand = significand; - vfp_double_dump("pack: overflow", vd); -#endif - } - - /* - * If any of the low bits (which will be shifted out of the - * number) are non-zero, the result is inexact. - */ - if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) - exceptions |= FPSCR_IXC; - - /* - * Do our rounding. - */ - significand += incr; - - /* - * Infinity? - */ - if (exponent >= 2046) { - exceptions |= FPSCR_OFC | FPSCR_IXC; - if (incr == 0) { - vd->exponent = 2045; - vd->significand = 0x7fffffffffffffffULL; - } else { - vd->exponent = 2047; /* infinity */ - vd->significand = 0; - } - } else { - if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) - exponent = 0; - if (exponent || significand > 0x8000000000000000ULL) - underflow = 0; - if (underflow) - exceptions |= FPSCR_UFC; - vd->exponent = exponent; - vd->significand = significand >> 1; - } - - pack: - vfp_double_dump("pack: final", vd); - { - s64 d = vfp_double_pack(vd); - pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, - dd, d, exceptions); - vfp_put_double(state, d, dd); - } - return exceptions; -} - -/* - * Propagate the NaN, setting exceptions if it is signalling. - * 'n' is always a NaN. 'm' may be a number, NaN or infinity. - */ -static u32 -vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, - struct vfp_double *vdm, u32 fpscr) -{ - struct vfp_double *nan; - int tn, tm = 0; - - tn = vfp_double_type(vdn); - - if (vdm) - tm = vfp_double_type(vdm); - - if (fpscr & FPSCR_DEFAULT_NAN) - /* - * Default NaN mode - always returns a quiet NaN - */ - nan = &vfp_double_default_qnan; - else { - /* - * Contemporary mode - select the first signalling - * NAN, or if neither are signalling, the first - * quiet NAN. - */ - if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) - nan = vdn; - else - nan = vdm; - /* - * Make the NaN quiet. - */ - nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; - } - - *vdd = *nan; - - /* - * If one was a signalling NAN, raise invalid operation. - */ - return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; -} - -/* - * Extended operations - */ -static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); - return 0; -} - -static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - vfp_put_double(state, vfp_get_double(state, dm), dd); - return 0; -} - -static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); - return 0; -} - -static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - struct vfp_double vdm, vdd, *vdp; - int ret, tm; - - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - tm = vfp_double_type(&vdm); - if (tm & (VFP_NAN|VFP_INFINITY)) { - vdp = &vdd; - - if (tm & VFP_NAN) - ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr); - else if (vdm.sign == 0) { - sqrt_copy: - vdp = &vdm; - ret = 0; - } else { - sqrt_invalid: - vdp = &vfp_double_default_qnan; - ret = FPSCR_IOC; - } - vfp_put_double(state, vfp_double_pack(vdp), dd); - return ret; - } - - /* - * sqrt(+/- 0) == +/- 0 - */ - if (tm & VFP_ZERO) - goto sqrt_copy; - - /* - * Normalise a denormalised number - */ - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - /* - * sqrt(<0) = invalid - */ - if (vdm.sign) - goto sqrt_invalid; - - vfp_double_dump("sqrt", &vdm); - - /* - * Estimate the square root. - */ - vdd.sign = 0; - vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; - vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; - - vfp_double_dump("sqrt estimate1", &vdd); - - vdm.significand >>= 1 + (vdm.exponent & 1); - vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); - - vfp_double_dump("sqrt estimate2", &vdd); - - /* - * And now adjust. - */ - if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { - if (vdd.significand < 2) { - vdd.significand = ~0ULL; - } else { - u64 termh, terml, remh, reml; - vdm.significand <<= 2; - mul64to128(&termh, &terml, vdd.significand, vdd.significand); - sub128(&remh, &reml, vdm.significand, 0, termh, terml); - while ((s64)remh < 0) { - vdd.significand -= 1; - shift64left(&termh, &terml, vdd.significand); - terml |= 1; - add128(&remh, &reml, remh, reml, termh, terml); - } - vdd.significand |= (remh | reml) != 0; - } - } - vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); -} - -/* - * Equal := ZC - * Less than := N - * Greater than := C - * Unordered := CV - */ -static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) -{ - s64 d, m; - u32 ret = 0; - - pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr); - m = vfp_get_double(state, dm); - if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { - ret |= FPSCR_C | FPSCR_V; - if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - d = vfp_get_double(state, dd); - if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { - ret |= FPSCR_C | FPSCR_V; - if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (ret == 0) { - //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m); - if (d == m || vfp_double_packed_abs(d | m) == 0) { - /* - * equal - */ - ret |= FPSCR_Z | FPSCR_C; - //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); - } else if (vfp_double_packed_sign(d ^ m)) { - /* - * different signs - */ - if (vfp_double_packed_sign(d)) - /* - * d is negative, so d < m - */ - ret |= FPSCR_N; - else - /* - * d is positive, so d > m - */ - ret |= FPSCR_C; - } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { - /* - * d < m - */ - ret |= FPSCR_N; - } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { - /* - * d > m - */ - ret |= FPSCR_C; - } - } - pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret); - - return ret; -} - -static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_compare(state, dd, 0, dm, fpscr); -} - -static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_compare(state, dd, 1, dm, fpscr); -} - -static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); -} - -static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); -} - -static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) -{ - struct vfp_double vdm; - struct vfp_single vsd; - int tm; - u32 exceptions = 0; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - - tm = vfp_double_type(&vdm); - - /* - * If we have a signalling NaN, signal invalid operation. - */ - if (tm == VFP_SNAN) - exceptions = FPSCR_IOC; - - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - vsd.sign = vdm.sign; - vsd.significand = vfp_hi64to32jamming(vdm.significand); - - /* - * If we have an infinity or a NaN, the exponent must be 255 - */ - if (tm & (VFP_INFINITY|VFP_NAN)) { - vsd.exponent = 255; - if (tm == VFP_QNAN) - vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; - goto pack_nan; - } else if (tm & VFP_ZERO) - vsd.exponent = 0; - else - vsd.exponent = vdm.exponent - (1023 - 127); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); - - pack_nan: - vfp_put_float(state, vfp_single_pack(&vsd), sd); - return exceptions; -} - -static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - struct vfp_double vdm; - u32 m = vfp_get_float(state, dm); - - pr_debug("In %s\n", __FUNCTION__); - vdm.sign = 0; - vdm.exponent = 1023 + 63 - 1; - vdm.significand = (u64)m; - - return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); -} - -static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - struct vfp_double vdm; - u32 m = vfp_get_float(state, dm); - - pr_debug("In %s\n", __FUNCTION__); - vdm.sign = (m & 0x80000000) >> 16; - vdm.exponent = 1023 + 63 - 1; - vdm.significand = vdm.sign ? -m : m; - - return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); -} - -static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) -{ - struct vfp_double vdm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - - /* - * Do we have a denormalised number? - */ - tm = vfp_double_type(&vdm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) - vdm.sign = 0; - - if (vdm.exponent >= 1023 + 32) { - d = vdm.sign ? 0 : 0xffffffff; - exceptions = FPSCR_IOC; - } else if (vdm.exponent >= 1023 - 1) { - int shift = 1023 + 63 - vdm.exponent; - u64 rem, incr = 0; - - /* - * 2^0 <= m < 2^32-2^8 - */ - d = (vdm.significand << 1) >> shift; - rem = vdm.significand << (65 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x8000000000000000ULL; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { - incr = ~0ULL; - } - - if ((rem + incr) < rem) { - if (d < 0xffffffff) - d += 1; - else - exceptions |= FPSCR_IOC; - } - - if (d && vdm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - } else { - d = 0; - if (vdm.exponent | vdm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) - d = 1; - else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } - } - } - - pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); - - vfp_put_float(state, d, sd); - - return exceptions; -} - -static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); -} - -static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) -{ - struct vfp_double vdm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - vfp_double_dump("VDM", &vdm); - - /* - * Do we have denormalised number? - */ - tm = vfp_double_type(&vdm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (vdm.exponent >= 1023 + 32) { - d = 0x7fffffff; - if (vdm.sign) - d = ~d; - exceptions |= FPSCR_IOC; - } else if (vdm.exponent >= 1023 - 1) { - int shift = 1023 + 63 - vdm.exponent; /* 58 */ - u64 rem, incr = 0; - - d = (vdm.significand << 1) >> shift; - rem = vdm.significand << (65 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x8000000000000000ULL; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { - incr = ~0ULL; - } - - if ((rem + incr) < rem && d < 0xffffffff) - d += 1; - if (d > 0x7fffffff + (vdm.sign != 0)) { - d = 0x7fffffff + (vdm.sign != 0); - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - - if (vdm.sign) - d = -d; - } else { - d = 0; - if (vdm.exponent | vdm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) - d = 1; - else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) - d = -1; - } - } - - pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); - - vfp_put_float(state, (s32)d, sd); - - return exceptions; -} - -static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); -} - -static struct op fops_ext[] = { - { vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY - { vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS - { vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG - { vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP - { vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE - { vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ - { vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT - { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO - { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI - { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ - { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI - { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ -}; - - - - -static u32 -vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn, - struct vfp_double *vdm, u32 fpscr) -{ - struct vfp_double *vdp; - u32 exceptions = 0; - int tn, tm; - - tn = vfp_double_type(vdn); - tm = vfp_double_type(vdm); - - if (tn & tm & VFP_INFINITY) { - /* - * Two infinities. Are they different signs? - */ - if (vdn->sign ^ vdm->sign) { - /* - * different signs -> invalid - */ - exceptions = FPSCR_IOC; - vdp = &vfp_double_default_qnan; - } else { - /* - * same signs -> valid - */ - vdp = vdn; - } - } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { - /* - * One infinity and one number -> infinity - */ - vdp = vdn; - } else { - /* - * 'n' is a NaN of some type - */ - return vfp_propagate_nan(vdd, vdn, vdm, fpscr); - } - *vdd = *vdp; - return exceptions; -} - -static u32 -vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, - struct vfp_double *vdm, u32 fpscr) -{ - u32 exp_diff; - u64 m_sig; - - if (vdn->significand & (1ULL << 63) || - vdm->significand & (1ULL << 63)) { - pr_info("VFP: bad FP values\n"); - vfp_double_dump("VDN", vdn); - vfp_double_dump("VDM", vdm); - } - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vdn->exponent < vdm->exponent) { - struct vfp_double *t = vdn; - vdn = vdm; - vdm = t; - } - - /* - * Is 'n' an infinity or a NaN? Note that 'm' may be a number, - * infinity or a NaN here. - */ - if (vdn->exponent == 2047) - return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); - - /* - * We have two proper numbers, where 'vdn' is the larger magnitude. - * - * Copy 'n' to 'd' before doing the arithmetic. - */ - *vdd = *vdn; - - /* - * Align 'm' with the result. - */ - exp_diff = vdn->exponent - vdm->exponent; - m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); - - /* - * If the signs are different, we are really subtracting. - */ - if (vdn->sign ^ vdm->sign) { - m_sig = vdn->significand - m_sig; - if ((s64)m_sig < 0) { - vdd->sign = vfp_sign_negate(vdd->sign); - m_sig = -m_sig; - } else if (m_sig == 0) { - vdd->sign = (fpscr & FPSCR_RMODE_MASK) == - FPSCR_ROUND_MINUSINF ? 0x8000 : 0; - } - } else { - m_sig += vdn->significand; - } - vdd->significand = m_sig; - - return 0; -} - -static u32 -vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, - struct vfp_double *vdm, u32 fpscr) -{ - vfp_double_dump("VDN", vdn); - vfp_double_dump("VDM", vdm); - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vdn->exponent < vdm->exponent) { - struct vfp_double *t = vdn; - vdn = vdm; - vdm = t; - pr_debug("VFP: swapping M <-> N\n"); - } - - vdd->sign = vdn->sign ^ vdm->sign; - - /* - * If 'n' is an infinity or NaN, handle it. 'm' may be anything. - */ - if (vdn->exponent == 2047) { - if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) - return vfp_propagate_nan(vdd, vdn, vdm, fpscr); - if ((vdm->exponent | vdm->significand) == 0) { - *vdd = vfp_double_default_qnan; - return FPSCR_IOC; - } - vdd->exponent = vdn->exponent; - vdd->significand = 0; - return 0; - } - - /* - * If 'm' is zero, the result is always zero. In this case, - * 'n' may be zero or a number, but it doesn't matter which. - */ - if ((vdm->exponent | vdm->significand) == 0) { - vdd->exponent = 0; - vdd->significand = 0; - return 0; - } - - /* - * We add 2 to the destination exponent for the same reason - * as the addition case - though this time we have +1 from - * each input operand. - */ - vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; - vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); - - vfp_double_dump("VDD", vdd); - return 0; -} - -#define NEG_MULTIPLY (1 << 0) -#define NEG_SUBTRACT (1 << 1) - -static u32 -vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, const char *func) -{ - struct vfp_double vdd, vdp, vdn, vdm; - u32 exceptions; - - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); - if (negate & NEG_MULTIPLY) - vdp.sign = vfp_sign_negate(vdp.sign); - - vfp_double_unpack(&vdn, vfp_get_double(state, dd)); - if (negate & NEG_SUBTRACT) - vdn.sign = vfp_sign_negate(vdn.sign); - - exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); -} - -/* - * Standard operations - */ - -/* - * sd = sd + (sn * sm) - */ -static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); -} - -/* - * sd = sd - (sn * sm) - */ -static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); -} - -/* - * sd = -sd + (sn * sm) - */ -static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); -} - -/* - * sd = -sd - (sn * sm) - */ -static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - pr_debug("In %s\n", __FUNCTION__); - return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); -} - -/* - * sd = sn * sm - */ -static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - struct vfp_double vdd, vdn, vdm; - u32 exceptions; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); -} - -/* - * sd = -(sn * sm) - */ -static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - struct vfp_double vdd, vdn, vdm; - u32 exceptions; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); - vdd.sign = vfp_sign_negate(vdd.sign); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); -} - -/* - * sd = sn + sm - */ -static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - struct vfp_double vdd, vdn, vdm; - u32 exceptions; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); -} - -/* - * sd = sn - sm - */ -static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - struct vfp_double vdd, vdn, vdm; - u32 exceptions; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - if (vdn.exponent == 0 && vdn.significand) - vfp_double_normalise_denormal(&vdn); - - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - if (vdm.exponent == 0 && vdm.significand) - vfp_double_normalise_denormal(&vdm); - - /* - * Subtraction is like addition, but with a negated operand. - */ - vdm.sign = vfp_sign_negate(vdm.sign); - - exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); -} - -/* - * sd = sn / sm - */ -static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) -{ - struct vfp_double vdd, vdn, vdm; - u32 exceptions = 0; - int tm, tn; - - pr_debug("In %s\n", __FUNCTION__); - vfp_double_unpack(&vdn, vfp_get_double(state, dn)); - vfp_double_unpack(&vdm, vfp_get_double(state, dm)); - - vdd.sign = vdn.sign ^ vdm.sign; - - tn = vfp_double_type(&vdn); - tm = vfp_double_type(&vdm); - - /* - * Is n a NAN? - */ - if (tn & VFP_NAN) - goto vdn_nan; - - /* - * Is m a NAN? - */ - if (tm & VFP_NAN) - goto vdm_nan; - - /* - * If n and m are infinity, the result is invalid - * If n and m are zero, the result is invalid - */ - if (tm & tn & (VFP_INFINITY|VFP_ZERO)) - goto invalid; - - /* - * If n is infinity, the result is infinity - */ - if (tn & VFP_INFINITY) - goto infinity; - - /* - * If m is zero, raise div0 exceptions - */ - if (tm & VFP_ZERO) - goto divzero; - - /* - * If m is infinity, or n is zero, the result is zero - */ - if (tm & VFP_INFINITY || tn & VFP_ZERO) - goto zero; - - if (tn & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdn); - if (tm & VFP_DENORMAL) - vfp_double_normalise_denormal(&vdm); - - /* - * Ok, we have two numbers, we can perform division. - */ - vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; - vdm.significand <<= 1; - if (vdm.significand <= (2 * vdn.significand)) { - vdn.significand >>= 1; - vdd.exponent++; - } - vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); - if ((vdd.significand & 0x1ff) <= 2) { - u64 termh, terml, remh, reml; - mul64to128(&termh, &terml, vdm.significand, vdd.significand); - sub128(&remh, &reml, vdn.significand, 0, termh, terml); - while ((s64)remh < 0) { - vdd.significand -= 1; - add128(&remh, &reml, remh, reml, 0, vdm.significand); - } - vdd.significand |= (reml != 0); - } - return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); - - vdn_nan: - exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); - pack: - vfp_put_double(state, vfp_double_pack(&vdd), dd); - return exceptions; - - vdm_nan: - exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); - goto pack; - - zero: - vdd.exponent = 0; - vdd.significand = 0; - goto pack; - - divzero: - exceptions = FPSCR_DZC; - infinity: - vdd.exponent = 2047; - vdd.significand = 0; - goto pack; - - invalid: - vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); - return FPSCR_IOC; -} - -static struct op fops[] = { - { vfp_double_fmac, 0 }, - { vfp_double_fmsc, 0 }, - { vfp_double_fmul, 0 }, - { vfp_double_fadd, 0 }, - { vfp_double_fnmac, 0 }, - { vfp_double_fnmsc, 0 }, - { vfp_double_fnmul, 0 }, - { vfp_double_fsub, 0 }, - { vfp_double_fdiv, 0 }, -}; - -#define FREG_BANK(x) ((x) & 0x0c) -#define FREG_IDX(x) ((x) & 3) - -u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) -{ - u32 op = inst & FOP_MASK; - u32 exceptions = 0; - unsigned int dest; - unsigned int dn = vfp_get_dn(inst); - unsigned int dm; - unsigned int vecitr, veclen, vecstride; - struct op *fop; - - pr_debug("In %s\n", __FUNCTION__); - vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); - - fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; - - /* - * fcvtds takes an sN register number as destination, not dN. - * It also always operates on scalars. - */ - if (fop->flags & OP_SD) - dest = vfp_get_sd(inst); - else - dest = vfp_get_dd(inst); - - /* - * f[us]ito takes a sN operand, not a dN operand. - */ - if (fop->flags & OP_SM) - dm = vfp_get_sm(inst); - else - dm = vfp_get_dm(inst); - - /* - * If destination bank is zero, vector length is always '1'. - * ARM DDI0100F C5.1.3, C5.3.2. - */ - if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0)) - veclen = 0; - else - veclen = fpscr & FPSCR_LENGTH_MASK; - - pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, - (veclen >> FPSCR_LENGTH_BIT) + 1); - - if (!fop->fn) { - printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst)); - goto invalid; - } - - for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { - u32 except; - char type; - - type = fop->flags & OP_SD ? 's' : 'd'; - if (op == FOP_EXT) - pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n", - vecitr >> FPSCR_LENGTH_BIT, - type, dest, dn, dm); - else - pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n", - vecitr >> FPSCR_LENGTH_BIT, - type, dest, dn, FOP_TO_IDX(op), dm); - - except = fop->fn(state, dest, dn, dm, fpscr); - pr_debug("VFP: itr%d: exceptions=%08x\n", - vecitr >> FPSCR_LENGTH_BIT, except); - - exceptions |= except; - - /* - * CHECK: It appears to be undefined whether we stop when - * we encounter an exception. We continue. - */ - dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3); - dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3); - if (FREG_BANK(dm) != 0) - dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3); - } - return exceptions; - - invalid: - return ~0; -} diff --git a/src/core/arm/interpreter/vfp/vfpsingle.cpp b/src/core/arm/interpreter/vfp/vfpsingle.cpp deleted file mode 100644 index 0fcc85266..000000000 --- a/src/core/arm/interpreter/vfp/vfpsingle.cpp +++ /dev/null @@ -1,1278 +0,0 @@ -/* - vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction - Copyright (C) 2003 Skyeye Develop Group - for help please send mail to <skyeye-developer@lists.gro.clinux.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -/* - * This code is derived in part from : - * - Android kernel - * - John R. Housers softfloat library, which - * carries the following notice: - * - * =========================================================================== - * This C source file is part of the SoftFloat IEC/IEEE Floating-point - * Arithmetic Package, Release 2. - * - * Written by John R. Hauser. This work was made possible in part by the - * International Computer Science Institute, located at Suite 600, 1947 Center - * Street, Berkeley, California 94704. Funding was partially provided by the - * National Science Foundation under grant MIP-9311980. The original version - * of this code was written as part of a project to build a fixed-point vector - * processor in collaboration with the University of California at Berkeley, - * overseen by Profs. Nelson Morgan and John Wawrzynek. More information - * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ - * arithmetic/softfloat.html'. - * - * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort - * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT - * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO - * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY - * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. - * - * Derivative works are acceptable, even for commercial purposes, so long as - * (1) they include prominent notice that the work is derivative, and (2) they - * include prominent notice akin to these three paragraphs for those parts of - * this code that are retained. - * =========================================================================== - */ - -#include "core/arm/interpreter/vfp/vfp_helper.h" -#include "core/arm/interpreter/vfp/asm_vfp.h" -#include "core/arm/interpreter/vfp/vfp.h" - -static struct vfp_single vfp_single_default_qnan = { - //.exponent = 255, - //.sign = 0, - //.significand = VFP_SINGLE_SIGNIFICAND_QNAN, -}; - -static void vfp_single_dump(const char *str, struct vfp_single *s) -{ - pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n", - str, s->sign != 0, s->exponent, s->significand); -} - -static void vfp_single_normalise_denormal(struct vfp_single *vs) -{ - int bits = 31 - vfp_fls(vs->significand); - - vfp_single_dump("normalise_denormal: in", vs); - - if (bits) { - vs->exponent -= bits - 1; - vs->significand <<= bits; - } - - vfp_single_dump("normalise_denormal: out", vs); -} - - -u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func) -{ - u32 significand, incr, rmode; - int exponent, shift, underflow; - - vfp_single_dump("pack: in", vs); - - /* - * Infinities and NaNs are a special case. - */ - if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) - goto pack; - - /* - * Special-case zero. - */ - if (vs->significand == 0) { - vs->exponent = 0; - goto pack; - } - - exponent = vs->exponent; - significand = vs->significand; - - /* - * Normalise first. Note that we shift the significand up to - * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least - * significant bit. - */ - shift = 32 - vfp_fls(significand); - if (shift < 32 && shift) { - exponent -= shift; - significand <<= shift; - } - -#if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: normalised", vs); -#endif - - /* - * Tiny number? - */ - underflow = exponent < 0; - if (underflow) { - significand = vfp_shiftright32jamming(significand, -exponent); - exponent = 0; -#if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: tiny number", vs); -#endif - if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) - underflow = 0; - } - - /* - * Select rounding increment. - */ - incr = 0; - rmode = fpscr & FPSCR_RMODE_MASK; - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 1 << VFP_SINGLE_LOW_BITS; - if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) - incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; - - pr_debug("VFP: rounding increment = 0x%08x\n", incr); - - /* - * Is our rounding going to overflow? - */ - if ((significand + incr) < significand) { - exponent += 1; - significand = (significand >> 1) | (significand & 1); - incr >>= 1; -#if 1 - vs->exponent = exponent; - vs->significand = significand; - vfp_single_dump("pack: overflow", vs); -#endif - } - - /* - * If any of the low bits (which will be shifted out of the - * number) are non-zero, the result is inexact. - */ - if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) - exceptions |= FPSCR_IXC; - - /* - * Do our rounding. - */ - significand += incr; - - /* - * Infinity? - */ - if (exponent >= 254) { - exceptions |= FPSCR_OFC | FPSCR_IXC; - if (incr == 0) { - vs->exponent = 253; - vs->significand = 0x7fffffff; - } else { - vs->exponent = 255; /* infinity */ - vs->significand = 0; - } - } else { - if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) - exponent = 0; - if (exponent || significand > 0x80000000) - underflow = 0; - if (underflow) - exceptions |= FPSCR_UFC; - vs->exponent = exponent; - vs->significand = significand >> 1; - } - - pack: - vfp_single_dump("pack: final", vs); - { - s32 d = vfp_single_pack(vs); -#if 1 - pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func, - sd, d, exceptions); -#endif - vfp_put_float(state, d, sd); - } - - return exceptions; -} - -/* - * Propagate the NaN, setting exceptions if it is signalling. - * 'n' is always a NaN. 'm' may be a number, NaN or infinity. - */ -static u32 -vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn, - struct vfp_single *vsm, u32 fpscr) -{ - struct vfp_single *nan; - int tn, tm = 0; - - tn = vfp_single_type(vsn); - - if (vsm) - tm = vfp_single_type(vsm); - - if (fpscr & FPSCR_DEFAULT_NAN) - /* - * Default NaN mode - always returns a quiet NaN - */ - nan = &vfp_single_default_qnan; - else { - /* - * Contemporary mode - select the first signalling - * NAN, or if neither are signalling, the first - * quiet NAN. - */ - if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) - nan = vsn; - else - nan = vsm; - /* - * Make the NaN quiet. - */ - nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; - } - - *vsd = *nan; - - /* - * If one was a signalling NAN, raise invalid operation. - */ - return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; -} - - -/* - * Extended operations - */ -static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - vfp_put_float(state, vfp_single_packed_abs(m), sd); - return 0; -} - -static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - vfp_put_float(state, m, sd); - return 0; -} - -static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - vfp_put_float(state, vfp_single_packed_negate(m), sd); - return 0; -} - -static const u16 sqrt_oddadjust[] = { - 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, - 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67 -}; - -static const u16 sqrt_evenadjust[] = { - 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, - 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002 -}; - -u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) -{ - int index; - u32 z, a; - - if ((significand & 0xc0000000) != 0x40000000) { - pr_debug("VFP: estimate_sqrt: invalid significand\n"); - } - - a = significand << 1; - index = (a >> 27) & 15; - if (exponent & 1) { - z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; - z = ((a / z) << 14) + (z << 15); - a >>= 1; - } else { - z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; - z = a / z + z; - z = (z >= 0x20000) ? 0xffff8000 : (z << 15); - if (z <= a) - return (s32)a >> 1; - } - { - u64 v = (u64)a << 31; - do_div(v, z); - return v + (z >> 1); - } -} - -static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - struct vfp_single vsm, vsd, *vsp; - int ret, tm; - - vfp_single_unpack(&vsm, m); - tm = vfp_single_type(&vsm); - if (tm & (VFP_NAN|VFP_INFINITY)) { - vsp = &vsd; - - if (tm & VFP_NAN) - ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr); - else if (vsm.sign == 0) { - sqrt_copy: - vsp = &vsm; - ret = 0; - } else { - sqrt_invalid: - vsp = &vfp_single_default_qnan; - ret = FPSCR_IOC; - } - vfp_put_float(state, vfp_single_pack(vsp), sd); - return ret; - } - - /* - * sqrt(+/- 0) == +/- 0 - */ - if (tm & VFP_ZERO) - goto sqrt_copy; - - /* - * Normalise a denormalised number - */ - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - /* - * sqrt(<0) = invalid - */ - if (vsm.sign) - goto sqrt_invalid; - - vfp_single_dump("sqrt", &vsm); - - /* - * Estimate the square root. - */ - vsd.sign = 0; - vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; - vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; - - vfp_single_dump("sqrt estimate", &vsd); - - /* - * And now adjust. - */ - if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { - if (vsd.significand < 2) { - vsd.significand = 0xffffffff; - } else { - u64 term; - s64 rem; - vsm.significand <<= !(vsm.exponent & 1); - term = (u64)vsd.significand * vsd.significand; - rem = ((u64)vsm.significand << 32) - term; - - pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem); - - while (rem < 0) { - vsd.significand -= 1; - rem += ((u64)vsd.significand << 1) | 1; - } - vsd.significand |= rem != 0; - } - } - vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); -} - -/* - * Equal := ZC - * Less than := N - * Greater than := C - * Unordered := CV - */ -static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) -{ - s32 d; - u32 ret = 0; - - d = vfp_get_float(state, sd); - if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { - ret |= FPSCR_C | FPSCR_V; - if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { - ret |= FPSCR_C | FPSCR_V; - if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) - /* - * Signalling NaN, or signalling on quiet NaN - */ - ret |= FPSCR_IOC; - } - - if (ret == 0) { - if (d == m || vfp_single_packed_abs(d | m) == 0) { - /* - * equal - */ - ret |= FPSCR_Z | FPSCR_C; - } else if (vfp_single_packed_sign(d ^ m)) { - /* - * different signs - */ - if (vfp_single_packed_sign(d)) - /* - * d is negative, so d < m - */ - ret |= FPSCR_N; - else - /* - * d is positive, so d > m - */ - ret |= FPSCR_C; - } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { - /* - * d < m - */ - ret |= FPSCR_N; - } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { - /* - * d > m - */ - ret |= FPSCR_C; - } - } - return ret; -} - -static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - return vfp_compare(state, sd, 0, m, fpscr); -} - -static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - return vfp_compare(state, sd, 1, m, fpscr); -} - -static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - return vfp_compare(state, sd, 0, 0, fpscr); -} - -static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - return vfp_compare(state, sd, 1, 0, fpscr); -} - -static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) -{ - struct vfp_single vsm; - struct vfp_double vdd; - int tm; - u32 exceptions = 0; - - vfp_single_unpack(&vsm, m); - - tm = vfp_single_type(&vsm); - - /* - * If we have a signalling NaN, signal invalid operation. - */ - if (tm == VFP_SNAN) - exceptions = FPSCR_IOC; - - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - vdd.sign = vsm.sign; - vdd.significand = (u64)vsm.significand << 32; - - /* - * If we have an infinity or NaN, the exponent must be 2047. - */ - if (tm & (VFP_INFINITY|VFP_NAN)) { - vdd.exponent = 2047; - if (tm == VFP_QNAN) - vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; - goto pack_nan; - } else if (tm & VFP_ZERO) - vdd.exponent = 0; - else - vdd.exponent = vsm.exponent + (1023 - 127); - - return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); - - pack_nan: - vfp_put_double(state, vfp_double_pack(&vdd), dd); - return exceptions; -} - -static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - struct vfp_single vs; - - vs.sign = 0; - vs.exponent = 127 + 31 - 1; - vs.significand = (u32)m; - - return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); -} - -static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - struct vfp_single vs; - - vs.sign = (m & 0x80000000) >> 16; - vs.exponent = 127 + 31 - 1; - vs.significand = vs.sign ? -m : m; - - return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); -} - -static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - struct vfp_single vsm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - vfp_single_unpack(&vsm, m); - vfp_single_dump("VSM", &vsm); - - /* - * Do we have a denormalised number? - */ - tm = vfp_single_type(&vsm); - if (tm & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) - vsm.sign = 0; - - if (vsm.exponent >= 127 + 32) { - d = vsm.sign ? 0 : 0xffffffff; - exceptions = FPSCR_IOC; - } else if (vsm.exponent >= 127 - 1) { - int shift = 127 + 31 - vsm.exponent; - u32 rem, incr = 0; - - /* - * 2^0 <= m < 2^32-2^8 - */ - d = (vsm.significand << 1) >> shift; - rem = vsm.significand << (33 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x80000000; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { - incr = ~0; - } - - if ((rem + incr) < rem) { - if (d < 0xffffffff) - d += 1; - else - exceptions |= FPSCR_IOC; - } - - if (d && vsm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - } else { - d = 0; - if (vsm.exponent | vsm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) - d = 1; - else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { - d = 0; - exceptions |= FPSCR_IOC; - } - } - } - - pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); - - vfp_put_float(state, d, sd); - - return exceptions; -} - -static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO); -} - -static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - struct vfp_single vsm; - u32 d, exceptions = 0; - int rmode = fpscr & FPSCR_RMODE_MASK; - int tm; - - vfp_single_unpack(&vsm, m); - vfp_single_dump("VSM", &vsm); - - /* - * Do we have a denormalised number? - */ - tm = vfp_single_type(&vsm); - if (vfp_single_type(&vsm) & VFP_DENORMAL) - exceptions |= FPSCR_IDC; - - if (tm & VFP_NAN) { - d = 0; - exceptions |= FPSCR_IOC; - } else if (vsm.exponent >= 127 + 32) { - /* - * m >= 2^31-2^7: invalid - */ - d = 0x7fffffff; - if (vsm.sign) - d = ~d; - exceptions |= FPSCR_IOC; - } else if (vsm.exponent >= 127 - 1) { - int shift = 127 + 31 - vsm.exponent; - u32 rem, incr = 0; - - /* 2^0 <= m <= 2^31-2^7 */ - d = (vsm.significand << 1) >> shift; - rem = vsm.significand << (33 - shift); - - if (rmode == FPSCR_ROUND_NEAREST) { - incr = 0x80000000; - if ((d & 1) == 0) - incr -= 1; - } else if (rmode == FPSCR_ROUND_TOZERO) { - incr = 0; - } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { - incr = ~0; - } - - if ((rem + incr) < rem && d < 0xffffffff) - d += 1; - if (d > 0x7fffffff + (vsm.sign != 0)) { - d = 0x7fffffff + (vsm.sign != 0); - exceptions |= FPSCR_IOC; - } else if (rem) - exceptions |= FPSCR_IXC; - - if (vsm.sign) - d = -d; - } else { - d = 0; - if (vsm.exponent | vsm.significand) { - exceptions |= FPSCR_IXC; - if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) - d = 1; - else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) - d = -1; - } - } - - pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); - - vfp_put_float(state, (s32)d, sd); - - return exceptions; -} - -static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) -{ - return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO); -} - -static struct op fops_ext[] = { - { vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY - { vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS - { vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG - { vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP - { vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE - { vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ - { vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT - { vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO - { vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { NULL, 0 }, - { vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI - { vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ - { vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI - { vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ -}; - - - - - -static u32 -vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn, - struct vfp_single *vsm, u32 fpscr) -{ - struct vfp_single *vsp; - u32 exceptions = 0; - int tn, tm; - - tn = vfp_single_type(vsn); - tm = vfp_single_type(vsm); - - if (tn & tm & VFP_INFINITY) { - /* - * Two infinities. Are they different signs? - */ - if (vsn->sign ^ vsm->sign) { - /* - * different signs -> invalid - */ - exceptions = FPSCR_IOC; - vsp = &vfp_single_default_qnan; - } else { - /* - * same signs -> valid - */ - vsp = vsn; - } - } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { - /* - * One infinity and one number -> infinity - */ - vsp = vsn; - } else { - /* - * 'n' is a NaN of some type - */ - return vfp_propagate_nan(vsd, vsn, vsm, fpscr); - } - *vsd = *vsp; - return exceptions; -} - -static u32 -vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn, - struct vfp_single *vsm, u32 fpscr) -{ - u32 exp_diff, m_sig; - - if (vsn->significand & 0x80000000 || - vsm->significand & 0x80000000) { - pr_info("VFP: bad FP values\n"); - vfp_single_dump("VSN", vsn); - vfp_single_dump("VSM", vsm); - } - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vsn->exponent < vsm->exponent) { - struct vfp_single *t = vsn; - vsn = vsm; - vsm = t; - } - - /* - * Is 'n' an infinity or a NaN? Note that 'm' may be a number, - * infinity or a NaN here. - */ - if (vsn->exponent == 255) - return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); - - /* - * We have two proper numbers, where 'vsn' is the larger magnitude. - * - * Copy 'n' to 'd' before doing the arithmetic. - */ - *vsd = *vsn; - - /* - * Align both numbers. - */ - exp_diff = vsn->exponent - vsm->exponent; - m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); - - /* - * If the signs are different, we are really subtracting. - */ - if (vsn->sign ^ vsm->sign) { - m_sig = vsn->significand - m_sig; - if ((s32)m_sig < 0) { - vsd->sign = vfp_sign_negate(vsd->sign); - m_sig = -m_sig; - } else if (m_sig == 0) { - vsd->sign = (fpscr & FPSCR_RMODE_MASK) == - FPSCR_ROUND_MINUSINF ? 0x8000 : 0; - } - } else { - m_sig = vsn->significand + m_sig; - } - vsd->significand = m_sig; - - return 0; -} - -static u32 -vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr) -{ - vfp_single_dump("VSN", vsn); - vfp_single_dump("VSM", vsm); - - /* - * Ensure that 'n' is the largest magnitude number. Note that - * if 'n' and 'm' have equal exponents, we do not swap them. - * This ensures that NaN propagation works correctly. - */ - if (vsn->exponent < vsm->exponent) { - struct vfp_single *t = vsn; - vsn = vsm; - vsm = t; - pr_debug("VFP: swapping M <-> N\n"); - } - - vsd->sign = vsn->sign ^ vsm->sign; - - /* - * If 'n' is an infinity or NaN, handle it. 'm' may be anything. - */ - if (vsn->exponent == 255) { - if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) - return vfp_propagate_nan(vsd, vsn, vsm, fpscr); - if ((vsm->exponent | vsm->significand) == 0) { - *vsd = vfp_single_default_qnan; - return FPSCR_IOC; - } - vsd->exponent = vsn->exponent; - vsd->significand = 0; - return 0; - } - - /* - * If 'm' is zero, the result is always zero. In this case, - * 'n' may be zero or a number, but it doesn't matter which. - */ - if ((vsm->exponent | vsm->significand) == 0) { - vsd->exponent = 0; - vsd->significand = 0; - return 0; - } - - /* - * We add 2 to the destination exponent for the same reason as - * the addition case - though this time we have +1 from each - * input operand. - */ - vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; - vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); - - vfp_single_dump("VSD", vsd); - return 0; -} - -#define NEG_MULTIPLY (1 << 0) -#define NEG_SUBTRACT (1 << 1) - -static u32 -vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, const char *func) -{ - struct vfp_single vsd, vsp, vsn, vsm; - u32 exceptions; - s32 v; - - v = vfp_get_float(state, sn); - pr_debug("VFP: s%u = %08x\n", sn, v); - vfp_single_unpack(&vsn, v); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); - - vfp_single_unpack(&vsm, m); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); - - exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); - if (negate & NEG_MULTIPLY) - vsp.sign = vfp_sign_negate(vsp.sign); - - v = vfp_get_float(state, sd); - pr_debug("VFP: s%u = %08x\n", sd, v); - vfp_single_unpack(&vsn, v); - if (negate & NEG_SUBTRACT) - vsn.sign = vfp_sign_negate(vsn.sign); - - exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); -} - -/* - * Standard operations - */ - -/* - * sd = sd + (sn * sm) - */ -static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); -} - -/* - * sd = sd - (sn * sm) - */ -static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); -} - -/* - * sd = -sd + (sn * sm) - */ -static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); -} - -/* - * sd = -sd - (sn * sm) - */ -static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); - return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); -} - -/* - * sd = sn * sm - */ -static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - struct vfp_single vsd, vsn, vsm; - u32 exceptions; - s32 n = vfp_get_float(state, sn); - - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n); - - vfp_single_unpack(&vsn, n); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); - - vfp_single_unpack(&vsm, m); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); - - exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); -} - -/* - * sd = -(sn * sm) - */ -static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - struct vfp_single vsd, vsn, vsm; - u32 exceptions; - s32 n = vfp_get_float(state, sn); - - pr_debug("VFP: s%u = %08x\n", sn, n); - - vfp_single_unpack(&vsn, n); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); - - vfp_single_unpack(&vsm, m); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); - - exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); - vsd.sign = vfp_sign_negate(vsd.sign); - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); -} - -/* - * sd = sn + sm - */ -static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - struct vfp_single vsd, vsn, vsm; - u32 exceptions; - s32 n = vfp_get_float(state, sn); - - pr_debug("VFP: s%u = %08x\n", sn, n); - - /* - * Unpack and normalise denormals. - */ - vfp_single_unpack(&vsn, n); - if (vsn.exponent == 0 && vsn.significand) - vfp_single_normalise_denormal(&vsn); - - vfp_single_unpack(&vsm, m); - if (vsm.exponent == 0 && vsm.significand) - vfp_single_normalise_denormal(&vsm); - - exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); -} - -/* - * sd = sn - sm - */ -static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); - /* - * Subtraction is addition with one sign inverted. - */ - return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr); -} - -/* - * sd = sn / sm - */ -static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) -{ - struct vfp_single vsd, vsn, vsm; - u32 exceptions = 0; - s32 n = vfp_get_float(state, sn); - int tm, tn; - - pr_debug("VFP: s%u = %08x\n", sn, n); - - vfp_single_unpack(&vsn, n); - vfp_single_unpack(&vsm, m); - - vsd.sign = vsn.sign ^ vsm.sign; - - tn = vfp_single_type(&vsn); - tm = vfp_single_type(&vsm); - - /* - * Is n a NAN? - */ - if (tn & VFP_NAN) - goto vsn_nan; - - /* - * Is m a NAN? - */ - if (tm & VFP_NAN) - goto vsm_nan; - - /* - * If n and m are infinity, the result is invalid - * If n and m are zero, the result is invalid - */ - if (tm & tn & (VFP_INFINITY|VFP_ZERO)) - goto invalid; - - /* - * If n is infinity, the result is infinity - */ - if (tn & VFP_INFINITY) - goto infinity; - - /* - * If m is zero, raise div0 exception - */ - if (tm & VFP_ZERO) - goto divzero; - - /* - * If m is infinity, or n is zero, the result is zero - */ - if (tm & VFP_INFINITY || tn & VFP_ZERO) - goto zero; - - if (tn & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsn); - if (tm & VFP_DENORMAL) - vfp_single_normalise_denormal(&vsm); - - /* - * Ok, we have two numbers, we can perform division. - */ - vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; - vsm.significand <<= 1; - if (vsm.significand <= (2 * vsn.significand)) { - vsn.significand >>= 1; - vsd.exponent++; - } - { - u64 significand = (u64)vsn.significand << 32; - do_div(significand, vsm.significand); - vsd.significand = significand; - } - if ((vsd.significand & 0x3f) == 0) - vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); - - return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); - - vsn_nan: - exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); - pack: - vfp_put_float(state, vfp_single_pack(&vsd), sd); - return exceptions; - - vsm_nan: - exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); - goto pack; - - zero: - vsd.exponent = 0; - vsd.significand = 0; - goto pack; - - divzero: - exceptions = FPSCR_DZC; - infinity: - vsd.exponent = 255; - vsd.significand = 0; - goto pack; - - invalid: - vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); - return FPSCR_IOC; -} - -static struct op fops[] = { - { vfp_single_fmac, 0 }, - { vfp_single_fmsc, 0 }, - { vfp_single_fmul, 0 }, - { vfp_single_fadd, 0 }, - { vfp_single_fnmac, 0 }, - { vfp_single_fnmsc, 0 }, - { vfp_single_fnmul, 0 }, - { vfp_single_fsub, 0 }, - { vfp_single_fdiv, 0 }, -}; - -#define FREG_BANK(x) ((x) & 0x18) -#define FREG_IDX(x) ((x) & 7) - -u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) -{ - u32 op = inst & FOP_MASK; - u32 exceptions = 0; - unsigned int dest; - unsigned int sn = vfp_get_sn(inst); - unsigned int sm = vfp_get_sm(inst); - unsigned int vecitr, veclen, vecstride; - struct op *fop; - pr_debug("In %s\n", __FUNCTION__); - - vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); - - fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; - - /* - * fcvtsd takes a dN register number as destination, not sN. - * Technically, if bit 0 of dd is set, this is an invalid - * instruction. However, we ignore this for efficiency. - * It also only operates on scalars. - */ - if (fop->flags & OP_DD) - dest = vfp_get_dd(inst); - else - dest = vfp_get_sd(inst); - - /* - * If destination bank is zero, vector length is always '1'. - * ARM DDI0100F C5.1.3, C5.3.2. - */ - if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0) - veclen = 0; - else - veclen = fpscr & FPSCR_LENGTH_MASK; - - pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, - (veclen >> FPSCR_LENGTH_BIT) + 1); - - if (!fop->fn) { - printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]); - exit(-1); - goto invalid; - } - - for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { - s32 m = vfp_get_float(state, sm); - u32 except; - char type; - - type = fop->flags & OP_DD ? 'd' : 's'; - if (op == FOP_EXT) - pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n", - vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, - sm, m); - else - pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n", - vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, - FOP_TO_IDX(op), sm, m); - - except = fop->fn(state, dest, sn, m, fpscr); - pr_debug("VFP: itr%d: exceptions=%08x\n", - vecitr >> FPSCR_LENGTH_BIT, except); - - exceptions |= except; - - /* - * CHECK: It appears to be undefined whether we stop when - * we encounter an exception. We continue. - */ - dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); - sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); - if (FREG_BANK(sm) != 0) - sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); - } - return exceptions; - - invalid: - return (u32)-1; -} diff --git a/src/core/arm/interpreter/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h index 0ca62780b..4dac1a8bf 100644 --- a/src/core/arm/interpreter/arm_regformat.h +++ b/src/core/arm/skyeye_common/arm_regformat.h @@ -99,5 +99,7 @@ enum arm_regno{ MAX_REG_NUM, }; -#define VFP_OFFSET(x) (x - VFP_BASE) +#define CP15(idx) (idx - CP15_BASE) +#define VFP_OFFSET(x) (x - VFP_BASE) + #endif diff --git a/src/core/arm/interpreter/armcpu.h b/src/core/arm/skyeye_common/armcpu.h index 6b5ea8566..3a029f0e7 100644 --- a/src/core/arm/interpreter/armcpu.h +++ b/src/core/arm/skyeye_common/armcpu.h @@ -20,16 +20,13 @@ #ifndef __ARM_CPU_H__ #define __ARM_CPU_H__ -//#include <skyeye_thread.h> -//#include <skyeye_obj.h> -//#include <skyeye_mach.h> -//#include <skyeye_exec.h> #include <stddef.h> #include <stdio.h> #include "common/thread.h" +#include "core/arm/skyeye_common/armdefs.h" typedef struct ARM_CPU_State_s { ARMul_State * core; diff --git a/src/core/arm/interpreter/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index dd5983be3..8e71948c6 100644 --- a/src/core/arm/interpreter/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -31,7 +31,7 @@ #include "arm_regformat.h" #include "common/platform.h" -#include "skyeye_defs.h" +#include "core/arm/skyeye_common/skyeye_defs.h" //AJ2D-------------------------------------------------------------------------- @@ -130,7 +130,7 @@ typedef unsigned long long uint64_t; #endif */ -#include "armmmu.h" +#include "core/arm/skyeye_common/armmmu.h" //#include "lcd/skyeye_lcd.h" @@ -367,7 +367,6 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model) int verbose; /* non-zero means print various messages like the banner */ - mmu_state_t mmu; int mmu_inited; //mem_state_t mem; /*remove io_state to skyeye_mach_*.c files */ diff --git a/src/core/arm/interpreter/armemu.h b/src/core/arm/skyeye_common/armemu.h index 36fb2d09b..c0f0270fe 100644 --- a/src/core/arm/interpreter/armemu.h +++ b/src/core/arm/skyeye_common/armemu.h @@ -18,7 +18,7 @@ #define __ARMEMU_H__ -#include "armdefs.h" +#include "core/arm/skyeye_common/armdefs.h" //#include "skyeye.h" //extern ARMword isize; diff --git a/src/core/arm/interpreter/armmmu.h b/src/core/arm/skyeye_common/armmmu.h index 818108c9c..30858f9ba 100644 --- a/src/core/arm/interpreter/armmmu.h +++ b/src/core/arm/skyeye_common/armmmu.h @@ -134,121 +134,4 @@ typedef enum fault_t } fault_t; -typedef struct mmu_ops_s -{ - /*initilization */ - int (*init) (ARMul_State * state); - /*free on exit */ - void (*exit) (ARMul_State * state); - /*read byte data */ - fault_t (*read_byte) (ARMul_State * state, ARMword va, - ARMword * data); - /*write byte data */ - fault_t (*write_byte) (ARMul_State * state, ARMword va, - ARMword data); - /*read halfword data */ - fault_t (*read_halfword) (ARMul_State * state, ARMword va, - ARMword * data); - /*write halfword data */ - fault_t (*write_halfword) (ARMul_State * state, ARMword va, - ARMword data); - /*read word data */ - fault_t (*read_word) (ARMul_State * state, ARMword va, - ARMword * data); - /*write word data */ - fault_t (*write_word) (ARMul_State * state, ARMword va, - ARMword data); - /*load instr */ - fault_t (*load_instr) (ARMul_State * state, ARMword va, - ARMword * instr); - /*mcr */ - ARMword (*mcr) (ARMul_State * state, ARMword instr, ARMword val); - /*mrc */ - ARMword (*mrc) (ARMul_State * state, ARMword instr, ARMword * val); - - /*ywc 2005-04-16 convert virtual address to physics address */ - int (*v2p_dbct) (ARMul_State * state, ARMword virt_addr, - ARMword * phys_addr); -} mmu_ops_t; - - -#include "core/arm/interpreter/mmu/tlb.h" -#include "core/arm/interpreter/mmu/rb.h" -#include "core/arm/interpreter/mmu/wb.h" -#include "core/arm/interpreter/mmu/cache.h" - -/*special process mmu.h*/ -#include "core/arm/interpreter/mmu/sa_mmu.h" -//#include "core/arm/interpreter/mmu/arm7100_mmu.h" -//#include "core/arm/interpreter/mmu/arm920t_mmu.h" -//#include "core/arm/interpreter/mmu/arm926ejs_mmu.h" -#include "core/arm/interpreter/mmu/arm1176jzf_s_mmu.h" -//#include "core/arm/interpreter/mmu/cortex_a9_mmu.h" - -typedef struct mmu_state_t -{ - ARMword control; - ARMword translation_table_base; -/* dyf 201-08-11 for arm1176 */ - ARMword auxiliary_control; - ARMword coprocessor_access_control; - ARMword translation_table_base0; - ARMword translation_table_base1; - ARMword translation_table_ctrl; -/* arm1176 end */ - - ARMword domain_access_control; - ARMword fault_status; - ARMword fault_statusi; /* prefetch fault status */ - ARMword fault_address; - ARMword last_domain; - ARMword process_id; - ARMword context_id; - ARMword thread_uro_id; - ARMword cache_locked_down; - ARMword tlb_locked_down; -//chy 2003-08-24 for xscale - ARMword cache_type; // 0 - ARMword aux_control; // 1 - ARMword copro_access; // 15 - - mmu_ops_t ops; - union - { - sa_mmu_t sa_mmu; - //arm7100_mmu_t arm7100_mmu; - //arm920t_mmu_t arm920t_mmu; - //arm926ejs_mmu_t arm926ejs_mmu; - } u; -} mmu_state_t; - -int mmu_init (ARMul_State * state); -int mmu_reset (ARMul_State * state); -void mmu_exit (ARMul_State * state); - -fault_t mmu_read_word (ARMul_State * state, ARMword virt_addr, - ARMword * data); -fault_t mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data); -fault_t mmu_load_instr (ARMul_State * state, ARMword virt_addr, - ARMword * instr); - -ARMword mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value); -void mmu_mcr (ARMul_State * state, ARMword instr, ARMword value); - -/*ywc 20050416*/ -int mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, - ARMword * phys_addr); - -fault_t -mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data); -fault_t -mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data); -fault_t -mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data); -fault_t -mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data); -fault_t -mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data); -fault_t -mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data); #endif /* _ARMMMU_H_ */ diff --git a/src/core/arm/interpreter/armos.h b/src/core/arm/skyeye_common/armos.h index 4b58801ad..ffdadcd1c 100644 --- a/src/core/arm/interpreter/armos.h +++ b/src/core/arm/skyeye_common/armos.h @@ -15,14 +15,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -//#include "bank_defs.h" -//#include "dyncom/defines.h" - -//typedef struct mmap_area{ -// mem_bank_t bank; -// void *mmap_addr; -// struct mmap_area *next; -//}mmap_area_t; +#include <stdint.h> #if FAST_MEMORY /* in user mode, mmap_base will be on initial brk, diff --git a/src/core/arm/interpreter/skyeye_defs.h b/src/core/arm/skyeye_common/skyeye_defs.h index b6713ebad..d4088383f 100644 --- a/src/core/arm/interpreter/skyeye_defs.h +++ b/src/core/arm/skyeye_common/skyeye_defs.h @@ -108,4 +108,6 @@ typedef struct generic_arch_s align_t alignment; } generic_arch_t; -#endif
\ No newline at end of file +typedef u32 addr_t; + +#endif diff --git a/src/core/arm/skyeye_common/skyeye_types.h b/src/core/arm/skyeye_common/skyeye_types.h new file mode 100644 index 000000000..e7f022f19 --- /dev/null +++ b/src/core/arm/skyeye_common/skyeye_types.h @@ -0,0 +1,55 @@ +/* + skyeye_types.h - some data types definition for skyeye debugger + Copyright (C) 2003 Skyeye Develop Group + for help please send mail to <skyeye-developer@lists.sf.linuxforum.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +/* + * 12/16/2006 Michael.Kang <blackfin.kang@gmail.com> + */ + +#ifndef __SKYEYE_TYPES_H +#define __SKYEYE_TYPES_H + +#include <stdint.h> + +/*default machine word length */ + +#ifndef __BEOS__ +/* To avoid the type conflict with the qemu */ +#ifndef QEMU +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +typedef int8_t sint8; +typedef int16_t sint16; +typedef int32_t sint32; +typedef int64_t sint64; +#endif + +typedef uint32_t address_t; +typedef uint32_t uinteger_t; +typedef int32_t integer_t; + +typedef uint32_t physical_address_t; +typedef uint32_t generic_address_t; + +#endif + +#endif diff --git a/src/core/arm/interpreter/vfp/asm_vfp.h b/src/core/arm/skyeye_common/vfp/asm_vfp.h index f4ab34fd4..f4ab34fd4 100644 --- a/src/core/arm/interpreter/vfp/asm_vfp.h +++ b/src/core/arm/skyeye_common/vfp/asm_vfp.h diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp new file mode 100644 index 000000000..454f60099 --- /dev/null +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp @@ -0,0 +1,397 @@ +/* + armvfp.c - ARM VFPv3 emulation unit + Copyright (C) 2003 Skyeye Develop Group + for help please send mail to <skyeye-developer@lists.gro.clinux.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Note: this file handles interface with arm core and vfp registers */ + +/* Opens debug for classic interpreter only */ +//#define DEBUG + +#include "common/common.h" + +#include "core/arm/skyeye_common/armdefs.h" +#include "core/arm/skyeye_common/vfp/vfp.h" + +#define DEBUG DBG + +//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */ + +unsigned +VFPInit (ARMul_State *state) +{ + state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | + VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; + state->VFP[VFP_OFFSET(VFP_FPEXC)] = 0; + state->VFP[VFP_OFFSET(VFP_FPSCR)] = 0; + + //persistent_state = state; + /* Reset only specify VFP_FPEXC_EN = '0' */ + + return 0; +} + +unsigned +VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value) +{ + /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (21, 23); + int Rt = BITS (12, 15); + int CRn = BITS (16, 19); + int CRm = BITS (0, 3); + int OPC_2 = BITS (5, 7); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + + if (CoProc == 10 || CoProc == 11) { +#define VFP_MRC_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MRC_TRANS + } + DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", + instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); + + return ARMul_CANT; +} + +unsigned +VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value) +{ + /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (21, 23); + int Rt = BITS (12, 15); + int CRn = BITS (16, 19); + int CRm = BITS (0, 3); + int OPC_2 = BITS (5, 7); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + if (CoProc == 10 || CoProc == 11) { +#define VFP_MCR_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MCR_TRANS + } + DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", + instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); + + return ARMul_CANT; +} + +unsigned +VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2) +{ + /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (4, 7); + int Rt = BITS (12, 15); + int Rt2 = BITS (16, 19); + int CRm = BITS (0, 3); + + if (CoProc == 10 || CoProc == 11) { +#define VFP_MRRC_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MRRC_TRANS + } + DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", + instr, CoProc, OPC_1, Rt, Rt2, CRm); + + return ARMul_CANT; +} + +unsigned +VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2) +{ + /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (4, 7); + int Rt = BITS (12, 15); + int Rt2 = BITS (16, 19); + int CRm = BITS (0, 3); + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + + if (CoProc == 11 || CoProc == 10) { +#define VFP_MCRR_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MCRR_TRANS + } + DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", + instr, CoProc, OPC_1, Rt, Rt2, CRm); + + return ARMul_CANT; +} + +unsigned +VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value) +{ + /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int CRd = BITS (12, 15); + int Rn = BITS (16, 19); + int imm8 = BITS (0, 7); + int P = BIT(24); + int U = BIT(23); + int D = BIT(22); + int W = BIT(21); + + /* TODO check access permission */ + + /* VSTM */ + if ( (P|U|D|W) == 0 ) { + DEBUG("In %s, UNDEFINED\n", __FUNCTION__); + exit(-1); + } + if (CoProc == 10 || CoProc == 11) { +#if 1 + if (P == 0 && U == 0 && W == 0) { + DEBUG("VSTM Related encodings\n"); + exit(-1); + } + if (P == U && W == 1) { + DEBUG("UNDEFINED\n"); + exit(-1); + } +#endif + +#define VFP_STC_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_STC_TRANS + } + DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", + instr, CoProc, CRd, Rn, imm8, P, U, D, W); + + return ARMul_CANT; +} + +unsigned +VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value) +{ + /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int CRd = BITS (12, 15); + int Rn = BITS (16, 19); + int imm8 = BITS (0, 7); + int P = BIT(24); + int U = BIT(23); + int D = BIT(22); + int W = BIT(21); + + /* TODO check access permission */ + + if ( (P|U|D|W) == 0 ) { + DEBUG("In %s, UNDEFINED\n", __FUNCTION__); + exit(-1); + } + if (CoProc == 10 || CoProc == 11) { +#define VFP_LDC_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_LDC_TRANS + } + DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", + instr, CoProc, CRd, Rn, imm8, P, U, D, W); + + return ARMul_CANT; +} + +unsigned +VFPCDP (ARMul_State * state, unsigned type, u32 instr) +{ + /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ + int CoProc = BITS (8, 11); /* 10 or 11 */ + int OPC_1 = BITS (20, 23); + int CRd = BITS (12, 15); + int CRn = BITS (16, 19); + int CRm = BITS (0, 3); + int OPC_2 = BITS (5, 7); + + //ichfly + /*if ((instr & 0x0FBF0FD0) == 0x0EB70AC0) //vcvt.f64.f32 d8, s16 (s is bit 0-3 and LSB bit 22) (d is bit 12 - 15 MSB is Bit 6) + { + struct vfp_double vdd; + struct vfp_single vsd; + int dn = BITS(12, 15) + (BIT(22) << 4); + int sd = (BITS(0, 3) << 1) + BIT(5); + s32 n = vfp_get_float(state, sd); + vfp_single_unpack(&vsd, n); + if (vsd.exponent & 0x80) + { + vdd.exponent = (vsd.exponent&~0x80) | 0x400; + } + else + { + vdd.exponent = vsd.exponent | 0x380; + } + vdd.sign = vsd.sign; + vdd.significand = (u64)(vsd.significand & ~0xC0000000) << 32; // I have no idea why but the 2 uppern bits are not from the significand + vfp_put_double(state, vfp_double_pack(&vdd), dn); + return ARMul_DONE; + } + if ((instr & 0x0FBF0FD0) == 0x0EB70BC0) //vcvt.f32.f64 s15, d6 + { + struct vfp_double vdd; + struct vfp_single vsd; + int sd = BITS(0, 3) + (BIT(5) << 4); + int dn = (BITS(12, 15) << 1) + BIT(22); + vfp_double_unpack(&vdd, vfp_get_double(state, sd)); + if (vdd.exponent & 0x400) //todo if the exponent is to low or to high for this convert + { + vsd.exponent = (vdd.exponent) | 0x80; + } + else + { + vsd.exponent = vdd.exponent & ~0x80; + } + vsd.exponent &= 0xFF; + // vsd.exponent = vdd.exponent >> 3; + vsd.sign = vdd.sign; + vsd.significand = ((u64)(vdd.significand ) >> 32)& ~0xC0000000; + vfp_put_float(state, vfp_single_pack(&vsd), dn); + return ARMul_DONE; + }*/ + + /* TODO check access permission */ + + /* CRn/opc1 CRm/opc2 */ + + if (CoProc == 10 || CoProc == 11) { +#define VFP_CDP_TRANS +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_CDP_TRANS + + int exceptions = 0; + if (CoProc == 10) + exceptions = vfp_single_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); + else + exceptions = vfp_double_cpdo(state, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); + + vfp_raise_exceptions(state, exceptions, instr, state->VFP[VFP_OFFSET(VFP_FPSCR)]); + + return ARMul_DONE; + } + DEBUG("Can't identify %x\n", instr); + return ARMul_CANT; +} + + +/* ----------- MRC ------------ */ +#define VFP_MRC_IMPL +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MRC_IMPL + +#define VFP_MRRC_IMPL +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MRRC_IMPL + + +/* ----------- MCR ------------ */ +#define VFP_MCR_IMPL +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MCR_IMPL + +#define VFP_MCRR_IMPL +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_MCRR_IMPL + +/* Memory operation are not inlined, as old Interpreter and Fast interpreter + don't have the same memory operation interface. + Old interpreter framework does one access to coprocessor per data, and + handles already data write, as well as address computation, + which is not the case for Fast interpreter. Therefore, implementation + of vfp instructions in old interpreter and fast interpreter are separate. */ + +/* ----------- STC ------------ */ +#define VFP_STC_IMPL +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_STC_IMPL + + +/* ----------- LDC ------------ */ +#define VFP_LDC_IMPL +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_LDC_IMPL + + +/* ----------- CDP ------------ */ +#define VFP_CDP_IMPL +#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" +#undef VFP_CDP_IMPL + +/* Miscellaneous functions */ +int32_t vfp_get_float(arm_core_t* state, unsigned int reg) +{ + DEBUG("VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]); + return state->ExtReg[reg]; +} + +void vfp_put_float(arm_core_t* state, int32_t val, unsigned int reg) +{ + DEBUG("VFP put float: s%d <= [%08x]\n", reg, val); + state->ExtReg[reg] = val; +} + +uint64_t vfp_get_double(arm_core_t* state, unsigned int reg) +{ + uint64_t result; + result = ((uint64_t) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; + DEBUG("VFP get double: s[%d-%d]=[%016llx]\n", reg*2+1, reg*2, result); + return result; +} + +void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg) +{ + DEBUG("VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg*2+1, reg*2, (uint32_t) (val>>32), (uint32_t) (val & 0xffffffff)); + state->ExtReg[reg*2] = (uint32_t) (val & 0xffffffff); + state->ExtReg[reg*2+1] = (uint32_t) (val>>32); +} + + + +/* + * Process bitmask of exception conditions. (from vfpmodule.c) + */ +void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) +{ + int si_code = 0; + + vfpdebug("VFP: raising exceptions %08x\n", exceptions); + + if (exceptions == VFP_EXCEPTION_ERROR) { + DEBUG("unhandled bounce %x\n", inst); + exit(-1); + return; + } + + /* + * If any of the status flags are set, update the FPSCR. + * Comparison instructions always return at least one of + * these flags set. + */ + if (exceptions & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V)) + fpscr &= ~(FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V); + + fpscr |= exceptions; + + state->VFP[VFP_OFFSET(VFP_FPSCR)] = fpscr; +} diff --git a/src/core/arm/interpreter/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index bbf4caeb0..7256701f3 100644 --- a/src/core/arm/interpreter/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h @@ -25,7 +25,7 @@ #define vfpdebug //printf -#include "core/arm/interpreter/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ +#include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ unsigned VFPInit (ARMul_State *state); unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value); @@ -88,21 +88,21 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); /* MRC */ -inline void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); -inline void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); -inline void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); -inline void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); -inline void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); +void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword *value); +void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value); +void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2); +void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm); +void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword imm); /* MCR */ -inline void VMSR(ARMul_State * state, ARMword reg, ARMword Rt); +void VMSR(ARMul_State * state, ARMword reg, ARMword Rt); /* STC */ -inline int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value); -inline int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value); -inline int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value); +int VSTM(ARMul_State * state, int type, ARMword instr, ARMword* value); +int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword* value); +int VSTR(ARMul_State * state, int type, ARMword instr, ARMword* value); /* LDC */ -inline int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value); -inline int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value); -inline int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value); +int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value); +int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value); +int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value); #ifdef __cplusplus } diff --git a/src/core/arm/interpreter/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index b222e79f1..b1949603a 100644 --- a/src/core/arm/interpreter/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h @@ -38,19 +38,13 @@ #include <stdint.h> #include <stdio.h> -#include "core/arm/interpreter/armdefs.h" - -#define u16 uint16_t -#define u32 uint32_t -#define u64 uint64_t -#define s16 int16_t -#define s32 int32_t -#define s64 int64_t +#include "common/common_types.h" +#include "core/arm/skyeye_common/armdefs.h" #define pr_info //printf #define pr_debug //printf -static u32 vfp_fls(int x); +static u32 fls(ARMword x); #define do_div(n, base) {n/=base;} /* From vfpinstr.h */ @@ -508,7 +502,7 @@ struct op { u32 flags; }; -static u32 vfp_fls(int x) +static u32 fls(ARMword x) { int r = 32; @@ -538,4 +532,9 @@ static u32 vfp_fls(int x) } +u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func); +u32 vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr); +u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn, struct vfp_double *vdm, u32 fpscr); +u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr); + #endif diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp new file mode 100644 index 000000000..765c1f6bc --- /dev/null +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp @@ -0,0 +1,1432 @@ +/* + vfp/vfpdouble.c - ARM VFPv3 emulation unit - SoftFloat double instruction + Copyright (C) 2003 Skyeye Develop Group + for help please send mail to <skyeye-developer@lists.gro.clinux.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * This code is derived in part from : + * - Android kernel + * - John R. Housers softfloat library, which + * carries the following notice: + * + * =========================================================================== + * This C source file is part of the SoftFloat IEC/IEEE Floating-point + * Arithmetic Package, Release 2. + * + * Written by John R. Hauser. This work was made possible in part by the + * International Computer Science Institute, located at Suite 600, 1947 Center + * Street, Berkeley, California 94704. Funding was partially provided by the + * National Science Foundation under grant MIP-9311980. The original version + * of this code was written as part of a project to build a fixed-point vector + * processor in collaboration with the University of California at Berkeley, + * overseen by Profs. Nelson Morgan and John Wawrzynek. More information + * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ + * arithmetic/softfloat.html'. + * + * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort + * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT + * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO + * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY + * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + * + * Derivative works are acceptable, even for commercial purposes, so long as + * (1) they include prominent notice that the work is derivative, and (2) they + * include prominent notice akin to these three paragraphs for those parts of + * this code that are retained. + * =========================================================================== + */ + +#include "core/arm/skyeye_common/vfp/vfp.h" +#include "core/arm/skyeye_common/vfp/vfp_helper.h" +#include "core/arm/skyeye_common/vfp/asm_vfp.h" + +static struct vfp_double vfp_double_default_qnan = { + 2047, + 0, + VFP_DOUBLE_SIGNIFICAND_QNAN, +}; + +static void vfp_double_dump(const char *str, struct vfp_double *d) +{ + pr_debug("VFP: %s: sign=%d exponent=%d significand=%016llx\n", + str, d->sign != 0, d->exponent, d->significand); +} + +static void vfp_double_normalise_denormal(struct vfp_double *vd) +{ + int bits = 31 - fls((ARMword)(vd->significand >> 32)); + if (bits == 31) + bits = 63 - fls((ARMword)vd->significand); + + vfp_double_dump("normalise_denormal: in", vd); + + if (bits) { + vd->exponent -= bits - 1; + vd->significand <<= bits; + } + + vfp_double_dump("normalise_denormal: out", vd); +} + +u32 vfp_double_normaliseroundintern(ARMul_State* state, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) +{ + u64 significand, incr; + int exponent, shift, underflow; + u32 rmode; + + vfp_double_dump("pack: in", vd); + + /* + * Infinities and NaNs are a special case. + */ + if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) + goto pack; + + /* + * Special-case zero. + */ + if (vd->significand == 0) { + vd->exponent = 0; + goto pack; + } + + exponent = vd->exponent; + significand = vd->significand; + + shift = 32 - fls((ARMword)(significand >> 32)); + if (shift == 32) + shift = 64 - fls((ARMword)significand); + if (shift) { + exponent -= shift; + significand <<= shift; + } + +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: normalised", vd); +#endif + + /* + * Tiny number? + */ + underflow = exponent < 0; + if (underflow) { + significand = vfp_shiftright64jamming(significand, -exponent); + exponent = 0; +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: tiny number", vd); +#endif + if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) + underflow = 0; + } + + /* + * Select rounding increment. + */ + incr = 0; + rmode = fpscr & FPSCR_RMODE_MASK; + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 1ULL << VFP_DOUBLE_LOW_BITS; + if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) + incr -= 1; + } + else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } + else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) + incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; + + pr_debug("VFP: rounding increment = 0x%08llx\n", incr); + + /* + * Is our rounding going to overflow? + */ + if ((significand + incr) < significand) { + exponent += 1; + significand = (significand >> 1) | (significand & 1); + incr >>= 1; +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: overflow", vd); +#endif + } + + /* + * If any of the low bits (which will be shifted out of the + * number) are non-zero, the result is inexact. + */ + if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) + exceptions |= FPSCR_IXC; + + /* + * Do our rounding. + */ + significand += incr; + + /* + * Infinity? + */ + if (exponent >= 2046) { + exceptions |= FPSCR_OFC | FPSCR_IXC; + if (incr == 0) { + vd->exponent = 2045; + vd->significand = 0x7fffffffffffffffULL; + } + else { + vd->exponent = 2047; /* infinity */ + vd->significand = 0; + } + } + else { + if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) + exponent = 0; + if (exponent || significand > 0x8000000000000000ULL) + underflow = 0; + if (underflow) + exceptions |= FPSCR_UFC; + vd->exponent = exponent; + vd->significand = significand >> 1; + } + pack: + return 0; +} + +u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, u32 fpscr, u32 exceptions, const char *func) +{ + u64 significand, incr; + int exponent, shift, underflow; + u32 rmode; + + vfp_double_dump("pack: in", vd); + + /* + * Infinities and NaNs are a special case. + */ + if (vd->exponent == 2047 && (vd->significand == 0 || exceptions)) + goto pack; + + /* + * Special-case zero. + */ + if (vd->significand == 0) { + vd->exponent = 0; + goto pack; + } + + exponent = vd->exponent; + significand = vd->significand; + + shift = 32 - fls((ARMword)(significand >> 32)); + if (shift == 32) + shift = 64 - fls((ARMword)significand); + if (shift) { + exponent -= shift; + significand <<= shift; + } + +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: normalised", vd); +#endif + + /* + * Tiny number? + */ + underflow = exponent < 0; + if (underflow) { + significand = vfp_shiftright64jamming(significand, -exponent); + exponent = 0; +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: tiny number", vd); +#endif + if (!(significand & ((1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1))) + underflow = 0; + } + + /* + * Select rounding increment. + */ + incr = 0; + rmode = fpscr & FPSCR_RMODE_MASK; + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 1ULL << VFP_DOUBLE_LOW_BITS; + if ((significand & (1ULL << (VFP_DOUBLE_LOW_BITS + 1))) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) + incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; + + pr_debug("VFP: rounding increment = 0x%08llx\n", incr); + + /* + * Is our rounding going to overflow? + */ + if ((significand + incr) < significand) { + exponent += 1; + significand = (significand >> 1) | (significand & 1); + incr >>= 1; +#if 1 + vd->exponent = exponent; + vd->significand = significand; + vfp_double_dump("pack: overflow", vd); +#endif + } + + /* + * If any of the low bits (which will be shifted out of the + * number) are non-zero, the result is inexact. + */ + if (significand & ((1 << (VFP_DOUBLE_LOW_BITS + 1)) - 1)) + exceptions |= FPSCR_IXC; + + /* + * Do our rounding. + */ + significand += incr; + + /* + * Infinity? + */ + if (exponent >= 2046) { + exceptions |= FPSCR_OFC | FPSCR_IXC; + if (incr == 0) { + vd->exponent = 2045; + vd->significand = 0x7fffffffffffffffULL; + } else { + vd->exponent = 2047; /* infinity */ + vd->significand = 0; + } + } else { + if (significand >> (VFP_DOUBLE_LOW_BITS + 1) == 0) + exponent = 0; + if (exponent || significand > 0x8000000000000000ULL) + underflow = 0; + if (underflow) + exceptions |= FPSCR_UFC; + vd->exponent = exponent; + vd->significand = significand >> 1; + } + +pack: + vfp_double_dump("pack: final", vd); + { + s64 d = vfp_double_pack(vd); + pr_debug("VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, + dd, d, exceptions); + vfp_put_double(state, d, dd); + } + return exceptions; +} + +/* + * Propagate the NaN, setting exceptions if it is signalling. + * 'n' is always a NaN. 'm' may be a number, NaN or infinity. + */ +static u32 +vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, + struct vfp_double *vdm, u32 fpscr) +{ + struct vfp_double *nan; + int tn, tm = 0; + + tn = vfp_double_type(vdn); + + if (vdm) + tm = vfp_double_type(vdm); + + if (fpscr & FPSCR_DEFAULT_NAN) + /* + * Default NaN mode - always returns a quiet NaN + */ + nan = &vfp_double_default_qnan; + else { + /* + * Contemporary mode - select the first signalling + * NAN, or if neither are signalling, the first + * quiet NAN. + */ + if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) + nan = vdn; + else + nan = vdm; + /* + * Make the NaN quiet. + */ + nan->significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; + } + + *vdd = *nan; + + /* + * If one was a signalling NAN, raise invalid operation. + */ + return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; +} + +/* + * Extended operations + */ +static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); + return 0; +} + +static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + vfp_put_double(state, vfp_get_double(state, dm), dd); + return 0; +} + +static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); + return 0; +} + +static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + vfp_double vdm, vdd, *vdp; + int ret, tm; + + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + tm = vfp_double_type(&vdm); + if (tm & (VFP_NAN|VFP_INFINITY)) { + vdp = &vdd; + + if (tm & VFP_NAN) + ret = vfp_propagate_nan(vdp, &vdm, NULL, fpscr); + else if (vdm.sign == 0) { +sqrt_copy: + vdp = &vdm; + ret = 0; + } else { +sqrt_invalid: + vdp = &vfp_double_default_qnan; + ret = FPSCR_IOC; + } + vfp_put_double(state, vfp_double_pack(vdp), dd); + return ret; + } + + /* + * sqrt(+/- 0) == +/- 0 + */ + if (tm & VFP_ZERO) + goto sqrt_copy; + + /* + * Normalise a denormalised number + */ + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + /* + * sqrt(<0) = invalid + */ + if (vdm.sign) + goto sqrt_invalid; + + vfp_double_dump("sqrt", &vdm); + + /* + * Estimate the square root. + */ + vdd.sign = 0; + vdd.exponent = ((vdm.exponent - 1023) >> 1) + 1023; + vdd.significand = (u64)vfp_estimate_sqrt_significand(vdm.exponent, vdm.significand >> 32) << 31; + + vfp_double_dump("sqrt estimate1", &vdd); + + vdm.significand >>= 1 + (vdm.exponent & 1); + vdd.significand += 2 + vfp_estimate_div128to64(vdm.significand, 0, vdd.significand); + + vfp_double_dump("sqrt estimate2", &vdd); + + /* + * And now adjust. + */ + if ((vdd.significand & VFP_DOUBLE_LOW_BITS_MASK) <= 5) { + if (vdd.significand < 2) { + vdd.significand = ~0ULL; + } else { + u64 termh, terml, remh, reml; + vdm.significand <<= 2; + mul64to128(&termh, &terml, vdd.significand, vdd.significand); + sub128(&remh, &reml, vdm.significand, 0, termh, terml); + while ((s64)remh < 0) { + vdd.significand -= 1; + shift64left(&termh, &terml, vdd.significand); + terml |= 1; + add128(&remh, &reml, remh, reml, termh, terml); + } + vdd.significand |= (remh | reml) != 0; + } + } + vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); + + return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); +} + +/* + * Equal := ZC + * Less than := N + * Greater than := C + * Unordered := CV + */ +static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u32 fpscr) +{ + s64 d, m; + u32 ret = 0; + + pr_debug("In %s, state=0x%x, fpscr=0x%x\n", __FUNCTION__, state, fpscr); + m = vfp_get_double(state, dm); + if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_double_packed_mantissa(m) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + d = vfp_get_double(state, dd); + if (vfp_double_packed_exponent(d) == 2047 && vfp_double_packed_mantissa(d)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_double_packed_mantissa(d) & (1ULL << (VFP_DOUBLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (ret == 0) { + //printf("In %s, d=%lld, m =%lld\n ", __FUNCTION__, d, m); + if (d == m || vfp_double_packed_abs(d | m) == 0) { + /* + * equal + */ + ret |= FPSCR_Z | FPSCR_C; + //printf("In %s,1 ret=0x%x\n", __FUNCTION__, ret); + } else if (vfp_double_packed_sign(d ^ m)) { + /* + * different signs + */ + if (vfp_double_packed_sign(d)) + /* + * d is negative, so d < m + */ + ret |= FPSCR_N; + else + /* + * d is positive, so d > m + */ + ret |= FPSCR_C; + } else if ((vfp_double_packed_sign(d) != 0) ^ (d < m)) { + /* + * d < m + */ + ret |= FPSCR_N; + } else if ((vfp_double_packed_sign(d) != 0) ^ (d > m)) { + /* + * d > m + */ + ret |= FPSCR_C; + } + } + pr_debug("In %s, state=0x%x, ret=0x%x\n", __FUNCTION__, state, ret); + + return ret; +} + +static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_compare(state, dd, 0, dm, fpscr); +} + +static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_compare(state, dd, 1, dm, fpscr); +} + +static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); +} + +static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); +} + +u32 vfp_double_fcvtsinterncutting(ARMul_State* state, int sd, struct vfp_double* dm, u32 fpscr) //ichfly for internal use only +{ + struct vfp_single vsd; + int tm; + u32 exceptions = 0; + + pr_debug("In %s\n", __FUNCTION__); + + tm = vfp_double_type(dm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(dm); + + vsd.sign = dm->sign; + vsd.significand = vfp_hi64to32jamming(dm->significand); + + /* + * If we have an infinity or a NaN, the exponent must be 255 + */ + if (tm & (VFP_INFINITY | VFP_NAN)) { + vsd.exponent = 255; + if (tm == VFP_QNAN) + vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; + goto pack_nan; + } + else if (tm & VFP_ZERO) + vsd.exponent = 0; + else + vsd.exponent = dm->exponent - (1023 - 127); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); + +pack_nan: + vfp_put_float(state, vfp_single_pack(&vsd), sd); + return exceptions; +} + +static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + struct vfp_single vsd; + int tm; + u32 exceptions = 0; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + + tm = vfp_double_type(&vdm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + vsd.sign = vdm.sign; + vsd.significand = vfp_hi64to32jamming(vdm.significand); + + /* + * If we have an infinity or a NaN, the exponent must be 255 + */ + if (tm & (VFP_INFINITY|VFP_NAN)) { + vsd.exponent = 255; + if (tm == VFP_QNAN) + vsd.significand |= VFP_SINGLE_SIGNIFICAND_QNAN; + goto pack_nan; + } else if (tm & VFP_ZERO) + vsd.exponent = 0; + else + vsd.exponent = vdm.exponent - (1023 - 127); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); + +pack_nan: + vfp_put_float(state, vfp_single_pack(&vsd), sd); + return exceptions; +} + +static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + u32 m = vfp_get_float(state, dm); + + pr_debug("In %s\n", __FUNCTION__); + vdm.sign = 0; + vdm.exponent = 1023 + 63 - 1; + vdm.significand = (u64)m; + + return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); +} + +static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + u32 m = vfp_get_float(state, dm); + + pr_debug("In %s\n", __FUNCTION__); + vdm.sign = (m & 0x80000000) >> 16; + vdm.exponent = 1023 + 63 - 1; + vdm.significand = vdm.sign ? -m : m; + + return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); +} + +static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + + /* + * Do we have a denormalised number? + */ + tm = vfp_double_type(&vdm); + if (tm & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) + vdm.sign = 0; + + if (vdm.exponent >= 1023 + 32) { + d = vdm.sign ? 0 : 0xffffffff; + exceptions = FPSCR_IOC; + } else if (vdm.exponent >= 1023 - 1) { + int shift = 1023 + 63 - vdm.exponent; + u64 rem, incr = 0; + + /* + * 2^0 <= m < 2^32-2^8 + */ + d = (ARMword)((vdm.significand << 1) >> shift); + rem = vdm.significand << (65 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x8000000000000000ULL; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { + incr = ~0ULL; + } + + if ((rem + incr) < rem) { + if (d < 0xffffffff) + d += 1; + else + exceptions |= FPSCR_IOC; + } + + if (d && vdm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + } else { + d = 0; + if (vdm.exponent | vdm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } + } + } + + pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(state, d, sd); + + return exceptions; +} + +static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); +} + +static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) +{ + struct vfp_double vdm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + vfp_double_dump("VDM", &vdm); + + /* + * Do we have denormalised number? + */ + tm = vfp_double_type(&vdm); + if (tm & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (vdm.exponent >= 1023 + 32) { + d = 0x7fffffff; + if (vdm.sign) + d = ~d; + exceptions |= FPSCR_IOC; + } else if (vdm.exponent >= 1023 - 1) { + int shift = 1023 + 63 - vdm.exponent; /* 58 */ + u64 rem, incr = 0; + + d = (ARMword)((vdm.significand << 1) >> shift); + rem = vdm.significand << (65 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x8000000000000000ULL; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vdm.sign != 0)) { + incr = ~0ULL; + } + + if ((rem + incr) < rem && d < 0xffffffff) + d += 1; + if (d > (0x7fffffff + (vdm.sign != 0))) { + d = (0x7fffffff + (vdm.sign != 0)); + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + + if (vdm.sign) + d = -d; + } else { + d = 0; + if (vdm.exponent | vdm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vdm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vdm.sign) + d = -1; + } + } + + pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(state, (s32)d, sd); + + return exceptions; +} + +static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); +} + +static struct op fops_ext[] = { + { vfp_double_fcpy, 0 }, //0x00000000 - FEXT_FCPY + { vfp_double_fabs, 0 }, //0x00000001 - FEXT_FABS + { vfp_double_fneg, 0 }, //0x00000002 - FEXT_FNEG + { vfp_double_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { vfp_double_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP + { vfp_double_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE + { vfp_double_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ + { vfp_double_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { vfp_double_fcvts, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT + { vfp_double_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO + { vfp_double_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { vfp_double_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI + { vfp_double_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ + { vfp_double_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI + { vfp_double_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ +}; + + + + +static u32 +vfp_double_fadd_nonnumber(struct vfp_double *vdd, struct vfp_double *vdn, + struct vfp_double *vdm, u32 fpscr) +{ + struct vfp_double *vdp; + u32 exceptions = 0; + int tn, tm; + + tn = vfp_double_type(vdn); + tm = vfp_double_type(vdm); + + if (tn & tm & VFP_INFINITY) { + /* + * Two infinities. Are they different signs? + */ + if (vdn->sign ^ vdm->sign) { + /* + * different signs -> invalid + */ + exceptions = FPSCR_IOC; + vdp = &vfp_double_default_qnan; + } else { + /* + * same signs -> valid + */ + vdp = vdn; + } + } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { + /* + * One infinity and one number -> infinity + */ + vdp = vdn; + } else { + /* + * 'n' is a NaN of some type + */ + return vfp_propagate_nan(vdd, vdn, vdm, fpscr); + } + *vdd = *vdp; + return exceptions; +} + +u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_double *vdm, u32 fpscr) +{ + u32 exp_diff; + u64 m_sig; + + if (vdn->significand & (1ULL << 63) || + vdm->significand & (1ULL << 63)) { + pr_info("VFP: bad FP values in %s\n", __func__); + vfp_double_dump("VDN", vdn); + vfp_double_dump("VDM", vdm); + } + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vdn->exponent < vdm->exponent) { + struct vfp_double *t = vdn; + vdn = vdm; + vdm = t; + } + + /* + * Is 'n' an infinity or a NaN? Note that 'm' may be a number, + * infinity or a NaN here. + */ + if (vdn->exponent == 2047) + return vfp_double_fadd_nonnumber(vdd, vdn, vdm, fpscr); + + /* + * We have two proper numbers, where 'vdn' is the larger magnitude. + * + * Copy 'n' to 'd' before doing the arithmetic. + */ + *vdd = *vdn; + + /* + * Align 'm' with the result. + */ + exp_diff = vdn->exponent - vdm->exponent; + m_sig = vfp_shiftright64jamming(vdm->significand, exp_diff); + + /* + * If the signs are different, we are really subtracting. + */ + if (vdn->sign ^ vdm->sign) { + m_sig = vdn->significand - m_sig; + if ((s64)m_sig < 0) { + vdd->sign = vfp_sign_negate(vdd->sign); + m_sig = -m_sig; + } else if (m_sig == 0) { + vdd->sign = (fpscr & FPSCR_RMODE_MASK) == + FPSCR_ROUND_MINUSINF ? 0x8000 : 0; + } + } else { + m_sig += vdn->significand; + } + vdd->significand = m_sig; + + return 0; +} + +u32 +vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, + struct vfp_double *vdm, u32 fpscr) +{ + vfp_double_dump("VDN", vdn); + vfp_double_dump("VDM", vdm); + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vdn->exponent < vdm->exponent) { + struct vfp_double *t = vdn; + vdn = vdm; + vdm = t; + pr_debug("VFP: swapping M <-> N\n"); + } + + vdd->sign = vdn->sign ^ vdm->sign; + + /* + * If 'n' is an infinity or NaN, handle it. 'm' may be anything. + */ + if (vdn->exponent == 2047) { + if (vdn->significand || (vdm->exponent == 2047 && vdm->significand)) + return vfp_propagate_nan(vdd, vdn, vdm, fpscr); + if ((vdm->exponent | vdm->significand) == 0) { + *vdd = vfp_double_default_qnan; + return FPSCR_IOC; + } + vdd->exponent = vdn->exponent; + vdd->significand = 0; + return 0; + } + + /* + * If 'm' is zero, the result is always zero. In this case, + * 'n' may be zero or a number, but it doesn't matter which. + */ + if ((vdm->exponent | vdm->significand) == 0) { + vdd->exponent = 0; + vdd->significand = 0; + return 0; + } + + /* + * We add 2 to the destination exponent for the same reason + * as the addition case - though this time we have +1 from + * each input operand. + */ + vdd->exponent = vdn->exponent + vdm->exponent - 1023 + 2; + vdd->significand = vfp_hi64multiply64(vdn->significand, vdm->significand); + + vfp_double_dump("VDD", vdd); + return 0; +} + +#define NEG_MULTIPLY (1 << 0) +#define NEG_SUBTRACT (1 << 1) + +static u32 +vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 fpscr, u32 negate, char *func) +{ + struct vfp_double vdd, vdp, vdn, vdm; + u32 exceptions; + + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + exceptions = vfp_double_multiply(&vdp, &vdn, &vdm, fpscr); + if (negate & NEG_MULTIPLY) + vdp.sign = vfp_sign_negate(vdp.sign); + + vfp_double_unpack(&vdn, vfp_get_double(state, dd)); + if (negate & NEG_SUBTRACT) + vdn.sign = vfp_sign_negate(vdn.sign); + + exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); + + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); +} + +/* + * Standard operations + */ + +/* + * sd = sd + (sn * sm) + */ +static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); +} + +/* + * sd = sd - (sn * sm) + */ +static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); +} + +/* + * sd = -sd + (sn * sm) + */ +static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); +} + +/* + * sd = -sd - (sn * sm) + */ +static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + pr_debug("In %s\n", __FUNCTION__); + return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); +} + +/* + * sd = sn * sm + */ +static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); +} + +/* + * sd = -(sn * sm) + */ +static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + exceptions = vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); + vdd.sign = vfp_sign_negate(vdd.sign); + + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); +} + +/* + * sd = sn + sm + */ +static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); + + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); +} + +/* + * sd = sn - sm + */ +static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + if (vdn.exponent == 0 && vdn.significand) + vfp_double_normalise_denormal(&vdn); + + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + if (vdm.exponent == 0 && vdm.significand) + vfp_double_normalise_denormal(&vdm); + + /* + * Subtraction is like addition, but with a negated operand. + */ + vdm.sign = vfp_sign_negate(vdm.sign); + + exceptions = vfp_double_add(&vdd, &vdn, &vdm, fpscr); + + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); +} + +/* + * sd = sn / sm + */ +static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) +{ + struct vfp_double vdd, vdn, vdm; + u32 exceptions = 0; + int tm, tn; + + pr_debug("In %s\n", __FUNCTION__); + vfp_double_unpack(&vdn, vfp_get_double(state, dn)); + vfp_double_unpack(&vdm, vfp_get_double(state, dm)); + + vdd.sign = vdn.sign ^ vdm.sign; + + tn = vfp_double_type(&vdn); + tm = vfp_double_type(&vdm); + + /* + * Is n a NAN? + */ + if (tn & VFP_NAN) + goto vdn_nan; + + /* + * Is m a NAN? + */ + if (tm & VFP_NAN) + goto vdm_nan; + + /* + * If n and m are infinity, the result is invalid + * If n and m are zero, the result is invalid + */ + if (tm & tn & (VFP_INFINITY|VFP_ZERO)) + goto invalid; + + /* + * If n is infinity, the result is infinity + */ + if (tn & VFP_INFINITY) + goto infinity; + + /* + * If m is zero, raise div0 exceptions + */ + if (tm & VFP_ZERO) + goto divzero; + + /* + * If m is infinity, or n is zero, the result is zero + */ + if (tm & VFP_INFINITY || tn & VFP_ZERO) + goto zero; + + if (tn & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdn); + if (tm & VFP_DENORMAL) + vfp_double_normalise_denormal(&vdm); + + /* + * Ok, we have two numbers, we can perform division. + */ + vdd.exponent = vdn.exponent - vdm.exponent + 1023 - 1; + vdm.significand <<= 1; + if (vdm.significand <= (2 * vdn.significand)) { + vdn.significand >>= 1; + vdd.exponent++; + } + vdd.significand = vfp_estimate_div128to64(vdn.significand, 0, vdm.significand); + if ((vdd.significand & 0x1ff) <= 2) { + u64 termh, terml, remh, reml; + mul64to128(&termh, &terml, vdm.significand, vdd.significand); + sub128(&remh, &reml, vdn.significand, 0, termh, terml); + while ((s64)remh < 0) { + vdd.significand -= 1; + add128(&remh, &reml, remh, reml, 0, vdm.significand); + } + vdd.significand |= (reml != 0); + } + return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); + +vdn_nan: + exceptions = vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); +pack: + vfp_put_double(state, vfp_double_pack(&vdd), dd); + return exceptions; + +vdm_nan: + exceptions = vfp_propagate_nan(&vdd, &vdm, &vdn, fpscr); + goto pack; + +zero: + vdd.exponent = 0; + vdd.significand = 0; + goto pack; + +divzero: + exceptions = FPSCR_DZC; +infinity: + vdd.exponent = 2047; + vdd.significand = 0; + goto pack; + +invalid: + vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); + return FPSCR_IOC; +} + +static struct op fops[] = { + { vfp_double_fmac, 0 }, + { vfp_double_fmsc, 0 }, + { vfp_double_fmul, 0 }, + { vfp_double_fadd, 0 }, + { vfp_double_fnmac, 0 }, + { vfp_double_fnmsc, 0 }, + { vfp_double_fnmul, 0 }, + { vfp_double_fsub, 0 }, + { vfp_double_fdiv, 0 }, +}; + +#define FREG_BANK(x) ((x) & 0x0c) +#define FREG_IDX(x) ((x) & 3) + +u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) +{ + u32 op = inst & FOP_MASK; + u32 exceptions = 0; + unsigned int dest; + unsigned int dn = vfp_get_dn(inst); + unsigned int dm; + unsigned int vecitr, veclen, vecstride; + struct op *fop; + + pr_debug("In %s\n", __FUNCTION__); + vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); + + fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; + + /* + * fcvtds takes an sN register number as destination, not dN. + * It also always operates on scalars. + */ + if (fop->flags & OP_SD) + dest = vfp_get_sd(inst); + else + dest = vfp_get_dd(inst); + + /* + * f[us]ito takes a sN operand, not a dN operand. + */ + if (fop->flags & OP_SM) + dm = vfp_get_sm(inst); + else + dm = vfp_get_dm(inst); + + /* + * If destination bank is zero, vector length is always '1'. + * ARM DDI0100F C5.1.3, C5.3.2. + */ + if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0)) + veclen = 0; + else + veclen = fpscr & FPSCR_LENGTH_MASK; + + pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, + (veclen >> FPSCR_LENGTH_BIT) + 1); + + if (!fop->fn) { + printf("VFP: could not find double op %d\n", FEXT_TO_IDX(inst)); + goto invalid; + } + + for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { + u32 except; + char type; + + type = fop->flags & OP_SD ? 's' : 'd'; + if (op == FOP_EXT) + pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n", + vecitr >> FPSCR_LENGTH_BIT, + type, dest, dn, dm); + else + pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n", + vecitr >> FPSCR_LENGTH_BIT, + type, dest, dn, FOP_TO_IDX(op), dm); + + except = fop->fn(state, dest, dn, dm, fpscr); + pr_debug("VFP: itr%d: exceptions=%08x\n", + vecitr >> FPSCR_LENGTH_BIT, except); + + exceptions |= except; + + /* + * CHECK: It appears to be undefined whether we stop when + * we encounter an exception. We continue. + */ + dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 3); + dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 3); + if (FREG_BANK(dm) != 0) + dm = FREG_BANK(dm) + ((FREG_IDX(dm) + vecstride) & 3); + } + return exceptions; + +invalid: + return ~0; +} diff --git a/src/core/arm/interpreter/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index a57047911..45208fb13 100644 --- a/src/core/arm/interpreter/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp @@ -3709,7 +3709,7 @@ VFPLABEL_INST: { fault = check_address_validity(cpu, addr, &phys_addr, 0); if (fault) goto MMU_EXCEPTION; - fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); + fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); if (fault) goto MMU_EXCEPTION; DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d, cpu->ExtReg[inst_cream->d]); } @@ -3719,13 +3719,13 @@ VFPLABEL_INST: if (fault) goto MMU_EXCEPTION; /* Check endianness */ - fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d*2], 32); + fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d*2], 32); if (fault) goto MMU_EXCEPTION; fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); if (fault) goto MMU_EXCEPTION; - fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[inst_cream->d*2+1], 32); + fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[inst_cream->d*2+1], 32); if (fault) goto MMU_EXCEPTION; DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, inst_cream->d*2+1, inst_cream->d*2, cpu->ExtReg[inst_cream->d*2+1], cpu->ExtReg[inst_cream->d*2]); } @@ -3926,7 +3926,7 @@ VFPLABEL_INST: { fault = check_address_validity(cpu, addr, &phys_addr, 0); if (fault) goto MMU_EXCEPTION; - fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); + fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); if (fault) goto MMU_EXCEPTION; DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]); addr += 4; @@ -3936,12 +3936,12 @@ VFPLABEL_INST: /* Careful of endianness, little by default */ fault = check_address_validity(cpu, addr, &phys_addr, 0); if (fault) goto MMU_EXCEPTION; - fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); + fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); if (fault) goto MMU_EXCEPTION; fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); if (fault) goto MMU_EXCEPTION; - fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); + fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); if (fault) goto MMU_EXCEPTION; DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); addr += 8; @@ -4048,7 +4048,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc { if (single) { - //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); + //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); #if 0 phys_addr = get_phys_addr(cpu, bb, Addr, 0); bb = cpu->dyncom_engine->bb; @@ -4166,7 +4166,7 @@ VFPLABEL_INST: /* encoding 1 */ fault = check_address_validity(cpu, addr, &phys_addr, 0); if (fault) goto MMU_EXCEPTION; - fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); + fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); if (fault) goto MMU_EXCEPTION; DBG("\taddr[%x] <= s%d=[%x]\n", addr, inst_cream->d+i, cpu->ExtReg[inst_cream->d+i]); addr += 4; @@ -4177,13 +4177,13 @@ VFPLABEL_INST: /* encoding 1 */ fault = check_address_validity(cpu, addr, &phys_addr, 0); if (fault) goto MMU_EXCEPTION; - fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); + fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); if (fault) goto MMU_EXCEPTION; fault = check_address_validity(cpu, addr + 4, &phys_addr, 0); if (fault) goto MMU_EXCEPTION; - fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); + fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); if (fault) goto MMU_EXCEPTION; DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); addr += 8; @@ -4304,7 +4304,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc if (single) { - //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); + //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); /* if R(i) is R15? */ #if 0 phys_addr = get_phys_addr(cpu, bb, Addr, 0); @@ -4321,7 +4321,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc else { - //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); + //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); #if 0 phys_addr = get_phys_addr(cpu, bb, Addr, 0); bb = cpu->dyncom_engine->bb; @@ -4332,7 +4332,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc bb = cpu->dyncom_engine->bb; //if (fault) goto MMU_EXCEPTION; - //fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); + //fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); #if 0 phys_addr = get_phys_addr(cpu, bb, ADD(Addr, CONST(4)), 0); bb = cpu->dyncom_engine->bb; @@ -4431,7 +4431,7 @@ VFPLABEL_INST: fault = check_address_validity(cpu, addr, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr, phys_addr, value1, 32); + fault = interpreter_read_memory(addr, phys_addr, value1, 32); if (fault) goto MMU_EXCEPTION; DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, value1, addr); cpu->ExtReg[inst_cream->d+i] = value1; @@ -4443,13 +4443,13 @@ VFPLABEL_INST: fault = check_address_validity(cpu, addr, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr, phys_addr, value1, 32); + fault = interpreter_read_memory(addr, phys_addr, value1, 32); if (fault) goto MMU_EXCEPTION; fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr + 4, phys_addr, value2, 32); + fault = interpreter_read_memory(addr + 4, phys_addr, value2, 32); if (fault) goto MMU_EXCEPTION; DBG("\ts[%d-%d] <= [%x-%x] addr[%x-%x]\n", (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, value2, value1, addr+4, addr); cpu->ExtReg[(inst_cream->d+i)*2] = value1; @@ -4682,7 +4682,7 @@ VFPLABEL_INST: { fault = check_address_validity(cpu, addr, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); + fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d], 32); if (fault) goto MMU_EXCEPTION; DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d, cpu->ExtReg[inst_cream->d], addr); } @@ -4691,12 +4691,12 @@ VFPLABEL_INST: unsigned int word1, word2; fault = check_address_validity(cpu, addr, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr, phys_addr, word1, 32); + fault = interpreter_read_memory(addr, phys_addr, word1, 32); if (fault) goto MMU_EXCEPTION; fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr + 4, phys_addr, word2, 32); + fault = interpreter_read_memory(addr + 4, phys_addr, word2, 32); if (fault) goto MMU_EXCEPTION; /* Check endianness */ cpu->ExtReg[inst_cream->d*2] = word1; @@ -4923,7 +4923,7 @@ VFPLABEL_INST: { fault = check_address_validity(cpu, addr, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); + fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); if (fault) goto MMU_EXCEPTION; DBG("\ts%d <= [%x] addr[%x]\n", inst_cream->d+i, cpu->ExtReg[inst_cream->d+i], addr); addr += 4; @@ -4933,12 +4933,12 @@ VFPLABEL_INST: /* Careful of endianness, little by default */ fault = check_address_validity(cpu, addr, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); + fault = interpreter_read_memory(addr, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2], 32); if (fault) goto MMU_EXCEPTION; fault = check_address_validity(cpu, addr + 4, &phys_addr, 1); if (fault) goto MMU_EXCEPTION; - fault = interpreter_read_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); + fault = interpreter_read_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); if (fault) goto MMU_EXCEPTION; DBG("\ts[%d-%d] <= [%x-%x] addr[%x-%x]\n", (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2], addr+4, addr); addr += 8; @@ -5058,7 +5058,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc if (single) { - //fault = interpreter_write_memory(core, addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); + //fault = interpreter_write_memory(addr, phys_addr, cpu->ExtReg[inst_cream->d+i], 32); /* if R(i) is R15? */ #if 0 phys_addr = get_phys_addr(cpu, bb, Addr, 1); @@ -5095,7 +5095,7 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc val = new LoadInst(cpu->dyncom_engine->read_value, "", false, bb); LETFPS((d + i) * 2 + 1, FPBITCAST32(val)); - //fault = interpreter_write_memory(core, addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); + //fault = interpreter_write_memory(addr + 4, phys_addr, cpu->ExtReg[(inst_cream->d+i)*2 + 1], 32); //DBG("\taddr[%x-%x] <= s[%d-%d]=[%x-%x]\n", addr+4, addr, (inst_cream->d+i)*2+1, (inst_cream->d+i)*2, cpu->ExtReg[(inst_cream->d+i)*2+1], cpu->ExtReg[(inst_cream->d+i)*2]); //addr += 8; Addr = ADD(Addr, CONST(8)); diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp new file mode 100644 index 000000000..07d0c1f44 --- /dev/null +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp @@ -0,0 +1,1356 @@ +/* + vfp/vfpsingle.c - ARM VFPv3 emulation unit - SoftFloat single instruction + Copyright (C) 2003 Skyeye Develop Group + for help please send mail to <skyeye-developer@lists.gro.clinux.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * This code is derived in part from : + * - Android kernel + * - John R. Housers softfloat library, which + * carries the following notice: + * + * =========================================================================== + * This C source file is part of the SoftFloat IEC/IEEE Floating-point + * Arithmetic Package, Release 2. + * + * Written by John R. Hauser. This work was made possible in part by the + * International Computer Science Institute, located at Suite 600, 1947 Center + * Street, Berkeley, California 94704. Funding was partially provided by the + * National Science Foundation under grant MIP-9311980. The original version + * of this code was written as part of a project to build a fixed-point vector + * processor in collaboration with the University of California at Berkeley, + * overseen by Profs. Nelson Morgan and John Wawrzynek. More information + * is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ + * arithmetic/softfloat.html'. + * + * THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort + * has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT + * TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO + * PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY + * AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + * + * Derivative works are acceptable, even for commercial purposes, so long as + * (1) they include prominent notice that the work is derivative, and (2) they + * include prominent notice akin to these three paragraphs for those parts of + * this code that are retained. + * =========================================================================== + */ + +#include "core/arm/skyeye_common/vfp/vfp_helper.h" +#include "core/arm/skyeye_common/vfp/asm_vfp.h" +#include "core/arm/skyeye_common/vfp/vfp.h" + +static struct vfp_single vfp_single_default_qnan = { + 255, + 0, + VFP_SINGLE_SIGNIFICAND_QNAN, +}; + +static void vfp_single_dump(const char *str, struct vfp_single *s) +{ + pr_debug("VFP: %s: sign=%d exponent=%d significand=%08x\n", + str, s->sign != 0, s->exponent, s->significand); +} + +static void vfp_single_normalise_denormal(struct vfp_single *vs) +{ + int bits = 31 - fls(vs->significand); + + vfp_single_dump("normalise_denormal: in", vs); + + if (bits) { + vs->exponent -= bits - 1; + vs->significand <<= bits; + } + + vfp_single_dump("normalise_denormal: out", vs); +} + + +u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single *vs, u32 fpscr, u32 exceptions, const char *func) +{ + u32 significand, incr, rmode; + int exponent, shift, underflow; + + vfp_single_dump("pack: in", vs); + + /* + * Infinities and NaNs are a special case. + */ + if (vs->exponent == 255 && (vs->significand == 0 || exceptions)) + goto pack; + + /* + * Special-case zero. + */ + if (vs->significand == 0) { + vs->exponent = 0; + goto pack; + } + + exponent = vs->exponent; + significand = vs->significand; + + /* + * Normalise first. Note that we shift the significand up to + * bit 31, so we have VFP_SINGLE_LOW_BITS + 1 below the least + * significant bit. + */ + shift = 32 - fls(significand); + if (shift < 32 && shift) { + exponent -= shift; + significand <<= shift; + } + +#if 1 + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: normalised", vs); +#endif + + /* + * Tiny number? + */ + underflow = exponent < 0; + if (underflow) { + significand = vfp_shiftright32jamming(significand, -exponent); + exponent = 0; +#if 1 + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: tiny number", vs); +#endif + if (!(significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1))) + underflow = 0; + } + + /* + * Select rounding increment. + */ + incr = 0; + rmode = fpscr & FPSCR_RMODE_MASK; + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 1 << VFP_SINGLE_LOW_BITS; + if ((significand & (1 << (VFP_SINGLE_LOW_BITS + 1))) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vs->sign != 0)) + incr = (1 << (VFP_SINGLE_LOW_BITS + 1)) - 1; + + pr_debug("VFP: rounding increment = 0x%08x\n", incr); + + /* + * Is our rounding going to overflow? + */ + if ((significand + incr) < significand) { + exponent += 1; + significand = (significand >> 1) | (significand & 1); + incr >>= 1; +#if 1 + vs->exponent = exponent; + vs->significand = significand; + vfp_single_dump("pack: overflow", vs); +#endif + } + + /* + * If any of the low bits (which will be shifted out of the + * number) are non-zero, the result is inexact. + */ + if (significand & ((1 << (VFP_SINGLE_LOW_BITS + 1)) - 1)) + exceptions |= FPSCR_IXC; + + /* + * Do our rounding. + */ + significand += incr; + + /* + * Infinity? + */ + if (exponent >= 254) { + exceptions |= FPSCR_OFC | FPSCR_IXC; + if (incr == 0) { + vs->exponent = 253; + vs->significand = 0x7fffffff; + } else { + vs->exponent = 255; /* infinity */ + vs->significand = 0; + } + } else { + if (significand >> (VFP_SINGLE_LOW_BITS + 1) == 0) + exponent = 0; + if (exponent || significand > 0x80000000) + underflow = 0; + if (underflow) + exceptions |= FPSCR_UFC; + vs->exponent = exponent; + vs->significand = significand >> 1; + } + +pack: + vfp_single_dump("pack: final", vs); + { + s32 d = vfp_single_pack(vs); +#if 1 + pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func, + sd, d, exceptions); +#endif + vfp_put_float(state, d, sd); + } + + return exceptions; +} + +/* + * Propagate the NaN, setting exceptions if it is signalling. + * 'n' is always a NaN. 'm' may be a number, NaN or infinity. + */ +static u32 +vfp_propagate_nan(struct vfp_single *vsd, struct vfp_single *vsn, + struct vfp_single *vsm, u32 fpscr) +{ + struct vfp_single *nan; + int tn, tm = 0; + + tn = vfp_single_type(vsn); + + if (vsm) + tm = vfp_single_type(vsm); + + if (fpscr & FPSCR_DEFAULT_NAN) + /* + * Default NaN mode - always returns a quiet NaN + */ + nan = &vfp_single_default_qnan; + else { + /* + * Contemporary mode - select the first signalling + * NAN, or if neither are signalling, the first + * quiet NAN. + */ + if (tn == VFP_SNAN || (tm != VFP_SNAN && tn == VFP_QNAN)) + nan = vsn; + else + nan = vsm; + /* + * Make the NaN quiet. + */ + nan->significand |= VFP_SINGLE_SIGNIFICAND_QNAN; + } + + *vsd = *nan; + + /* + * If one was a signalling NAN, raise invalid operation. + */ + return tn == VFP_SNAN || tm == VFP_SNAN ? FPSCR_IOC : VFP_NAN_FLAG; +} + + +/* + * Extended operations + */ +static u32 vfp_single_fabs(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + vfp_put_float(state, vfp_single_packed_abs(m), sd); + return 0; +} + +static u32 vfp_single_fcpy(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + vfp_put_float(state, m, sd); + return 0; +} + +static u32 vfp_single_fneg(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + vfp_put_float(state, vfp_single_packed_negate(m), sd); + return 0; +} + +static const u16 sqrt_oddadjust[] = { + 0x0004, 0x0022, 0x005d, 0x00b1, 0x011d, 0x019f, 0x0236, 0x02e0, + 0x039c, 0x0468, 0x0545, 0x0631, 0x072b, 0x0832, 0x0946, 0x0a67 +}; + +static const u16 sqrt_evenadjust[] = { + 0x0a2d, 0x08af, 0x075a, 0x0629, 0x051a, 0x0429, 0x0356, 0x029e, + 0x0200, 0x0179, 0x0109, 0x00af, 0x0068, 0x0034, 0x0012, 0x0002 +}; + +u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand) +{ + int index; + u32 z, a; + + if ((significand & 0xc0000000) != 0x40000000) { + pr_debug("VFP: estimate_sqrt: invalid significand\n"); + } + + a = significand << 1; + index = (a >> 27) & 15; + if (exponent & 1) { + z = 0x4000 + (a >> 17) - sqrt_oddadjust[index]; + z = ((a / z) << 14) + (z << 15); + a >>= 1; + } else { + z = 0x8000 + (a >> 17) - sqrt_evenadjust[index]; + z = a / z + z; + z = (z >= 0x20000) ? 0xffff8000 : (z << 15); + if (z <= a) + return (s32)a >> 1; + } + { + u64 v = (u64)a << 31; + do_div(v, z); + return (u32)(v + (z >> 1)); + } +} + +static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vsm, vsd, *vsp; + int ret, tm; + + vfp_single_unpack(&vsm, m); + tm = vfp_single_type(&vsm); + if (tm & (VFP_NAN|VFP_INFINITY)) { + vsp = &vsd; + + if (tm & VFP_NAN) + ret = vfp_propagate_nan(vsp, &vsm, NULL, fpscr); + else if (vsm.sign == 0) { +sqrt_copy: + vsp = &vsm; + ret = 0; + } else { +sqrt_invalid: + vsp = &vfp_single_default_qnan; + ret = FPSCR_IOC; + } + vfp_put_float(state, vfp_single_pack(vsp), sd); + return ret; + } + + /* + * sqrt(+/- 0) == +/- 0 + */ + if (tm & VFP_ZERO) + goto sqrt_copy; + + /* + * Normalise a denormalised number + */ + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + /* + * sqrt(<0) = invalid + */ + if (vsm.sign) + goto sqrt_invalid; + + vfp_single_dump("sqrt", &vsm); + + /* + * Estimate the square root. + */ + vsd.sign = 0; + vsd.exponent = ((vsm.exponent - 127) >> 1) + 127; + vsd.significand = vfp_estimate_sqrt_significand(vsm.exponent, vsm.significand) + 2; + + vfp_single_dump("sqrt estimate", &vsd); + + /* + * And now adjust. + */ + if ((vsd.significand & VFP_SINGLE_LOW_BITS_MASK) <= 5) { + if (vsd.significand < 2) { + vsd.significand = 0xffffffff; + } else { + u64 term; + s64 rem; + vsm.significand <<= !(vsm.exponent & 1); + term = (u64)vsd.significand * vsd.significand; + rem = ((u64)vsm.significand << 32) - term; + + pr_debug("VFP: term=%016llx rem=%016llx\n", term, rem); + + while (rem < 0) { + vsd.significand -= 1; + rem += ((u64)vsd.significand << 1) | 1; + } + vsd.significand |= rem != 0; + } + } + vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); +} + +/* + * Equal := ZC + * Less than := N + * Greater than := C + * Unordered := CV + */ +static u32 vfp_compare(ARMul_State* state, int sd, int signal_on_qnan, s32 m, u32 fpscr) +{ + s32 d; + u32 ret = 0; + + d = vfp_get_float(state, sd); + if (vfp_single_packed_exponent(m) == 255 && vfp_single_packed_mantissa(m)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_single_packed_mantissa(m) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (vfp_single_packed_exponent(d) == 255 && vfp_single_packed_mantissa(d)) { + ret |= FPSCR_C | FPSCR_V; + if (signal_on_qnan || !(vfp_single_packed_mantissa(d) & (1 << (VFP_SINGLE_MANTISSA_BITS - 1)))) + /* + * Signalling NaN, or signalling on quiet NaN + */ + ret |= FPSCR_IOC; + } + + if (ret == 0) { + if (d == m || vfp_single_packed_abs(d | m) == 0) { + /* + * equal + */ + ret |= FPSCR_Z | FPSCR_C; + } else if (vfp_single_packed_sign(d ^ m)) { + /* + * different signs + */ + if (vfp_single_packed_sign(d)) + /* + * d is negative, so d < m + */ + ret |= FPSCR_N; + else + /* + * d is positive, so d > m + */ + ret |= FPSCR_C; + } else if ((vfp_single_packed_sign(d) != 0) ^ (d < m)) { + /* + * d < m + */ + ret |= FPSCR_N; + } else if ((vfp_single_packed_sign(d) != 0) ^ (d > m)) { + /* + * d > m + */ + ret |= FPSCR_C; + } + } + return ret; +} + +static u32 vfp_single_fcmp(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_compare(state, sd, 0, m, fpscr); +} + +static u32 vfp_single_fcmpe(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_compare(state, sd, 1, m, fpscr); +} + +static u32 vfp_single_fcmpz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_compare(state, sd, 0, 0, fpscr); +} + +static u32 vfp_single_fcmpez(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_compare(state, sd, 1, 0, fpscr); +} + +static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ichfly for internal use only +{ + struct vfp_single vsm; + struct vfp_double vdd; + int tm; + u32 exceptions = 0; + + vfp_single_unpack(&vsm, m); + + tm = vfp_single_type(&vsm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + vdd.sign = vsm.sign; + vdd.significand = (u64)vsm.significand << 32; + + /* + * If we have an infinity or NaN, the exponent must be 2047. + */ + if (tm & (VFP_INFINITY | VFP_NAN)) { + vdd.exponent = 2047; + if (tm == VFP_QNAN) + vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; + goto pack_nan; + } + else if (tm & VFP_ZERO) + vdd.exponent = 0; + else + vdd.exponent = vsm.exponent + (1023 - 127); +pack_nan: + vfp_double_normaliseroundintern(state, &vdd, fpscr, exceptions, "fcvtd"); + return vfp_double_pack(&vdd); +} + +static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vsm; + struct vfp_double vdd; + int tm; + u32 exceptions = 0; + + vfp_single_unpack(&vsm, m); + + tm = vfp_single_type(&vsm); + + /* + * If we have a signalling NaN, signal invalid operation. + */ + if (tm == VFP_SNAN) + exceptions = FPSCR_IOC; + + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + vdd.sign = vsm.sign; + vdd.significand = (u64)vsm.significand << 32; + + /* + * If we have an infinity or NaN, the exponent must be 2047. + */ + if (tm & (VFP_INFINITY|VFP_NAN)) { + vdd.exponent = 2047; + if (tm == VFP_QNAN) + vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; + goto pack_nan; + } else if (tm & VFP_ZERO) + vdd.exponent = 0; + else + vdd.exponent = vsm.exponent + (1023 - 127); + + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); + +pack_nan: + vfp_put_double(state, vfp_double_pack(&vdd), dd); + return exceptions; +} + +static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vs; + + vs.sign = 0; + vs.exponent = 127 + 31 - 1; + vs.significand = (u32)m; + + return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); +} + +static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vs; + + vs.sign = (m & 0x80000000) >> 16; + vs.exponent = 127 + 31 - 1; + vs.significand = vs.sign ? -m : m; + + return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); +} + +static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vsm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + vfp_single_unpack(&vsm, m); + vfp_single_dump("VSM", &vsm); + + /* + * Do we have a denormalised number? + */ + tm = vfp_single_type(&vsm); + if (tm & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) + vsm.sign = 0; + + if (vsm.exponent >= 127 + 32) { + d = vsm.sign ? 0 : 0xffffffff; + exceptions = FPSCR_IOC; + } else if (vsm.exponent >= 127 - 1) { + int shift = 127 + 31 - vsm.exponent; + u32 rem, incr = 0; + + /* + * 2^0 <= m < 2^32-2^8 + */ + d = (vsm.significand << 1) >> shift; + rem = vsm.significand << (33 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x80000000; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { + incr = ~0; + } + + if ((rem + incr) < rem) { + if (d < 0xffffffff) + d += 1; + else + exceptions |= FPSCR_IOC; + } + + if (d && vsm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + } else { + d = 0; + if (vsm.exponent | vsm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) { + d = 0; + exceptions |= FPSCR_IOC; + } + } + } + + pr_debug("VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(state, d, sd); + + return exceptions; +} + +static u32 vfp_single_ftouiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_single_ftoui(state, sd, unused, m, FPSCR_ROUND_TOZERO); +} + +static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + struct vfp_single vsm; + u32 d, exceptions = 0; + int rmode = fpscr & FPSCR_RMODE_MASK; + int tm; + + vfp_single_unpack(&vsm, m); + vfp_single_dump("VSM", &vsm); + + /* + * Do we have a denormalised number? + */ + tm = vfp_single_type(&vsm); + if (vfp_single_type(&vsm) & VFP_DENORMAL) + exceptions |= FPSCR_IDC; + + if (tm & VFP_NAN) { + d = 0; + exceptions |= FPSCR_IOC; + } else if (vsm.exponent >= 127 + 32) { + /* + * m >= 2^31-2^7: invalid + */ + d = 0x7fffffff; + if (vsm.sign) + d = ~d; + exceptions |= FPSCR_IOC; + } else if (vsm.exponent >= 127 - 1) { + int shift = 127 + 31 - vsm.exponent; + u32 rem, incr = 0; + + /* 2^0 <= m <= 2^31-2^7 */ + d = (vsm.significand << 1) >> shift; + rem = vsm.significand << (33 - shift); + + if (rmode == FPSCR_ROUND_NEAREST) { + incr = 0x80000000; + if ((d & 1) == 0) + incr -= 1; + } else if (rmode == FPSCR_ROUND_TOZERO) { + incr = 0; + } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vsm.sign != 0)) { + incr = ~0; + } + + if ((rem + incr) < rem && d < 0xffffffff) + d += 1; + if (d > (0x7fffffffu + (vsm.sign != 0))) { + d = (0x7fffffffu + (vsm.sign != 0)); + exceptions |= FPSCR_IOC; + } else if (rem) + exceptions |= FPSCR_IXC; + + if (vsm.sign) + d = 0-d; + } else { + d = 0; + if (vsm.exponent | vsm.significand) { + exceptions |= FPSCR_IXC; + if (rmode == FPSCR_ROUND_PLUSINF && vsm.sign == 0) + d = 1; + else if (rmode == FPSCR_ROUND_MINUSINF && vsm.sign) + d = -1; + } + } + + pr_debug("VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); + + vfp_put_float(state, (s32)d, sd); + + return exceptions; +} + +static u32 vfp_single_ftosiz(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) +{ + return vfp_single_ftosi(state, sd, unused, m, FPSCR_ROUND_TOZERO); +} + +static struct op fops_ext[] = { + { vfp_single_fcpy, 0 }, //0x00000000 - FEXT_FCPY + { vfp_single_fabs, 0 }, //0x00000001 - FEXT_FABS + { vfp_single_fneg, 0 }, //0x00000002 - FEXT_FNEG + { vfp_single_fsqrt, 0 }, //0x00000003 - FEXT_FSQRT + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { vfp_single_fcmp, OP_SCALAR }, //0x00000008 - FEXT_FCMP + { vfp_single_fcmpe, OP_SCALAR }, //0x00000009 - FEXT_FCMPE + { vfp_single_fcmpz, OP_SCALAR }, //0x0000000A - FEXT_FCMPZ + { vfp_single_fcmpez, OP_SCALAR }, //0x0000000B - FEXT_FCMPEZ + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { vfp_single_fcvtd, OP_SCALAR|OP_DD }, //0x0000000F - FEXT_FCVT + { vfp_single_fuito, OP_SCALAR }, //0x00000010 - FEXT_FUITO + { vfp_single_fsito, OP_SCALAR }, //0x00000011 - FEXT_FSITO + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { NULL, 0 }, + { vfp_single_ftoui, OP_SCALAR }, //0x00000018 - FEXT_FTOUI + { vfp_single_ftouiz, OP_SCALAR }, //0x00000019 - FEXT_FTOUIZ + { vfp_single_ftosi, OP_SCALAR }, //0x0000001A - FEXT_FTOSI + { vfp_single_ftosiz, OP_SCALAR }, //0x0000001B - FEXT_FTOSIZ +}; + + + + + +static u32 +vfp_single_fadd_nonnumber(struct vfp_single *vsd, struct vfp_single *vsn, + struct vfp_single *vsm, u32 fpscr) +{ + struct vfp_single *vsp; + u32 exceptions = 0; + int tn, tm; + + tn = vfp_single_type(vsn); + tm = vfp_single_type(vsm); + + if (tn & tm & VFP_INFINITY) { + /* + * Two infinities. Are they different signs? + */ + if (vsn->sign ^ vsm->sign) { + /* + * different signs -> invalid + */ + exceptions = FPSCR_IOC; + vsp = &vfp_single_default_qnan; + } else { + /* + * same signs -> valid + */ + vsp = vsn; + } + } else if (tn & VFP_INFINITY && tm & VFP_NUMBER) { + /* + * One infinity and one number -> infinity + */ + vsp = vsn; + } else { + /* + * 'n' is a NaN of some type + */ + return vfp_propagate_nan(vsd, vsn, vsm, fpscr); + } + *vsd = *vsp; + return exceptions; +} + +static u32 +vfp_single_add(struct vfp_single *vsd, struct vfp_single *vsn, + struct vfp_single *vsm, u32 fpscr) +{ + u32 exp_diff, m_sig; + + if (vsn->significand & 0x80000000 || + vsm->significand & 0x80000000) { + pr_info("VFP: bad FP values in %s\n", __func__); + vfp_single_dump("VSN", vsn); + vfp_single_dump("VSM", vsm); + } + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vsn->exponent < vsm->exponent) { + struct vfp_single *t = vsn; + vsn = vsm; + vsm = t; + } + + /* + * Is 'n' an infinity or a NaN? Note that 'm' may be a number, + * infinity or a NaN here. + */ + if (vsn->exponent == 255) + return vfp_single_fadd_nonnumber(vsd, vsn, vsm, fpscr); + + /* + * We have two proper numbers, where 'vsn' is the larger magnitude. + * + * Copy 'n' to 'd' before doing the arithmetic. + */ + *vsd = *vsn; + + /* + * Align both numbers. + */ + exp_diff = vsn->exponent - vsm->exponent; + m_sig = vfp_shiftright32jamming(vsm->significand, exp_diff); + + /* + * If the signs are different, we are really subtracting. + */ + if (vsn->sign ^ vsm->sign) { + m_sig = vsn->significand - m_sig; + if ((s32)m_sig < 0) { + vsd->sign = vfp_sign_negate(vsd->sign); + m_sig = 0-m_sig; + } else if (m_sig == 0) { + vsd->sign = (fpscr & FPSCR_RMODE_MASK) == + FPSCR_ROUND_MINUSINF ? 0x8000 : 0; + } + } else { + m_sig = vsn->significand + m_sig; + } + vsd->significand = m_sig; + + return 0; +} + +static u32 +vfp_single_multiply(struct vfp_single *vsd, struct vfp_single *vsn, struct vfp_single *vsm, u32 fpscr) +{ + vfp_single_dump("VSN", vsn); + vfp_single_dump("VSM", vsm); + + /* + * Ensure that 'n' is the largest magnitude number. Note that + * if 'n' and 'm' have equal exponents, we do not swap them. + * This ensures that NaN propagation works correctly. + */ + if (vsn->exponent < vsm->exponent) { + struct vfp_single *t = vsn; + vsn = vsm; + vsm = t; + pr_debug("VFP: swapping M <-> N\n"); + } + + vsd->sign = vsn->sign ^ vsm->sign; + + /* + * If 'n' is an infinity or NaN, handle it. 'm' may be anything. + */ + if (vsn->exponent == 255) { + if (vsn->significand || (vsm->exponent == 255 && vsm->significand)) + return vfp_propagate_nan(vsd, vsn, vsm, fpscr); + if ((vsm->exponent | vsm->significand) == 0) { + *vsd = vfp_single_default_qnan; + return FPSCR_IOC; + } + vsd->exponent = vsn->exponent; + vsd->significand = 0; + return 0; + } + + /* + * If 'm' is zero, the result is always zero. In this case, + * 'n' may be zero or a number, but it doesn't matter which. + */ + if ((vsm->exponent | vsm->significand) == 0) { + vsd->exponent = 0; + vsd->significand = 0; + return 0; + } + + /* + * We add 2 to the destination exponent for the same reason as + * the addition case - though this time we have +1 from each + * input operand. + */ + vsd->exponent = vsn->exponent + vsm->exponent - 127 + 2; + vsd->significand = vfp_hi64to32jamming((u64)vsn->significand * vsm->significand); + + vfp_single_dump("VSD", vsd); + return 0; +} + +#define NEG_MULTIPLY (1 << 0) +#define NEG_SUBTRACT (1 << 1) + +static u32 +vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr, u32 negate, char *func) +{ + + { + struct vfp_single vsd, vsp, vsn, vsm; + u32 exceptions; + s32 v; + + + + v = vfp_get_float(state, sn); + pr_debug("VFP: s%u = %08x\n", sn, v); + vfp_single_unpack(&vsn, v); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_multiply(&vsp, &vsn, &vsm, fpscr); + + if (negate & NEG_MULTIPLY) + vsp.sign = vfp_sign_negate(vsp.sign); + + v = vfp_get_float(state, sd); + pr_debug("VFP: s%u = %08x\n", sd, v); + vfp_single_unpack(&vsn, v); + if (negate & NEG_SUBTRACT) + vsn.sign = vfp_sign_negate(vsn.sign); + + exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); + } + + struct vfp_double vsd, vsp, vsn, vsm; + u32 exceptions; + s32 v; + s64 vd; + s64 md; + + v = vfp_get_float(state, sn); + vd = vfp_single_to_doubleintern(state, v, fpscr); + vfp_double_unpack(&vsn, vd); + + md = vfp_single_to_doubleintern(state, m, fpscr); + vfp_double_unpack(&vsm, md); + + exceptions = vfp_double_multiply(&vsp, &vsn, &vsm, fpscr); + if (negate & NEG_MULTIPLY) + vsp.sign = vfp_sign_negate(vsp.sign); + + v = vfp_get_float(state, sd); + vd = vfp_single_to_doubleintern(state, v, fpscr); + vfp_double_unpack(&vsn, vd); + + if (negate & NEG_SUBTRACT) + vsn.sign = vfp_sign_negate(vsn.sign); + + exceptions |= vfp_double_add(&vsd, &vsn, &vsp, fpscr); + + s64 debug = vfp_double_pack(&vsd); + + return vfp_double_fcvtsinterncutting(state, sd, &vsd, fpscr); + +} + +/* + * Standard operations + */ + +/* + * sd = sd + (sn * sm) + */ +static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); +} + +/* + * sd = sd - (sn * sm) + */ +static u32 vfp_single_fnmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sd, sn); + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_MULTIPLY, "fnmac"); +} + +/* + * sd = -sd + (sn * sm) + */ +static u32 vfp_single_fmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT, "fmsc"); +} + +/* + * sd = -sd - (sn * sm) + */ +static u32 vfp_single_fnmsc(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); +} + +/* + * sd = sn * sm + */ +static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(state, sn); + + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, n); + + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); +} + +/* + * sd = -(sn * sm) + */ +static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(state, sn); + + pr_debug("VFP: s%u = %08x\n", sn, n); + + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); + vsd.sign = vfp_sign_negate(vsd.sign); + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); +} + +/* + * sd = sn + sm + */ +static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + struct vfp_single vsd, vsn, vsm; + u32 exceptions; + s32 n = vfp_get_float(state, sn); + + pr_debug("VFP: s%u = %08x\n", sn, n); + + /* + * Unpack and normalise denormals. + */ + vfp_single_unpack(&vsn, n); + if (vsn.exponent == 0 && vsn.significand) + vfp_single_normalise_denormal(&vsn); + + vfp_single_unpack(&vsm, m); + if (vsm.exponent == 0 && vsm.significand) + vfp_single_normalise_denormal(&vsm); + + exceptions = vfp_single_add(&vsd, &vsn, &vsm, fpscr); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); +} + +/* + * sd = sn - sm + */ +static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + pr_debug("In %sVFP: s%u = %08x\n", __FUNCTION__, sn, sd); + /* + * Subtraction is addition with one sign inverted. + */ + return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr); +} + +/* + * sd = sn / sm + */ +static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) +{ + struct vfp_single vsd, vsn, vsm; + u32 exceptions = 0; + s32 n = vfp_get_float(state, sn); + int tm, tn; + + pr_debug("VFP: s%u = %08x\n", sn, n); + + vfp_single_unpack(&vsn, n); + vfp_single_unpack(&vsm, m); + + vsd.sign = vsn.sign ^ vsm.sign; + + tn = vfp_single_type(&vsn); + tm = vfp_single_type(&vsm); + + /* + * Is n a NAN? + */ + if (tn & VFP_NAN) + goto vsn_nan; + + /* + * Is m a NAN? + */ + if (tm & VFP_NAN) + goto vsm_nan; + + /* + * If n and m are infinity, the result is invalid + * If n and m are zero, the result is invalid + */ + if (tm & tn & (VFP_INFINITY|VFP_ZERO)) + goto invalid; + + /* + * If n is infinity, the result is infinity + */ + if (tn & VFP_INFINITY) + goto infinity; + + /* + * If m is zero, raise div0 exception + */ + if (tm & VFP_ZERO) + goto divzero; + + /* + * If m is infinity, or n is zero, the result is zero + */ + if (tm & VFP_INFINITY || tn & VFP_ZERO) + goto zero; + + if (tn & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsn); + if (tm & VFP_DENORMAL) + vfp_single_normalise_denormal(&vsm); + + /* + * Ok, we have two numbers, we can perform division. + */ + vsd.exponent = vsn.exponent - vsm.exponent + 127 - 1; + vsm.significand <<= 1; + if (vsm.significand <= (2 * vsn.significand)) { + vsn.significand >>= 1; + vsd.exponent++; + } + { + u64 significand = (u64)vsn.significand << 32; + do_div(significand, vsm.significand); + vsd.significand = (u32)significand; + } + if ((vsd.significand & 0x3f) == 0) + vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); + + return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); + +vsn_nan: + exceptions = vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); +pack: + vfp_put_float(state, vfp_single_pack(&vsd), sd); + return exceptions; + +vsm_nan: + exceptions = vfp_propagate_nan(&vsd, &vsm, &vsn, fpscr); + goto pack; + +zero: + vsd.exponent = 0; + vsd.significand = 0; + goto pack; + +divzero: + exceptions = FPSCR_DZC; +infinity: + vsd.exponent = 255; + vsd.significand = 0; + goto pack; + +invalid: + vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); + return FPSCR_IOC; +} + +static struct op fops[] = { + { vfp_single_fmac, 0 }, + { vfp_single_fmsc, 0 }, + { vfp_single_fmul, 0 }, + { vfp_single_fadd, 0 }, + { vfp_single_fnmac, 0 }, + { vfp_single_fnmsc, 0 }, + { vfp_single_fnmul, 0 }, + { vfp_single_fsub, 0 }, + { vfp_single_fdiv, 0 }, +}; + +#define FREG_BANK(x) ((x) & 0x18) +#define FREG_IDX(x) ((x) & 7) + +u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) +{ + u32 op = inst & FOP_MASK; + u32 exceptions = 0; + unsigned int dest; + unsigned int sn = vfp_get_sn(inst); + unsigned int sm = vfp_get_sm(inst); + unsigned int vecitr, veclen, vecstride; + struct op *fop; + pr_debug("In %s\n", __FUNCTION__); + + vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK); + + fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; + + /* + * fcvtsd takes a dN register number as destination, not sN. + * Technically, if bit 0 of dd is set, this is an invalid + * instruction. However, we ignore this for efficiency. + * It also only operates on scalars. + */ + if (fop->flags & OP_DD) + dest = vfp_get_dd(inst); + else + dest = vfp_get_sd(inst); + + /* + * If destination bank is zero, vector length is always '1'. + * ARM DDI0100F C5.1.3, C5.3.2. + */ + if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0) + veclen = 0; + else + veclen = fpscr & FPSCR_LENGTH_MASK; + + pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride, + (veclen >> FPSCR_LENGTH_BIT) + 1); + + if (!fop->fn) { + printf("VFP: could not find single op %d, inst=0x%x@0x%x\n", FEXT_TO_IDX(inst), inst, state->Reg[15]); + exit(-1); + goto invalid; + } + + for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) { + s32 m = vfp_get_float(state, sm); + u32 except; + char type; + + type = fop->flags & OP_DD ? 'd' : 's'; + if (op == FOP_EXT) + pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n", + vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, + sm, m); + else + pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n", + vecitr >> FPSCR_LENGTH_BIT, type, dest, sn, + FOP_TO_IDX(op), sm, m); + + except = fop->fn(state, dest, sn, m, fpscr); + pr_debug("VFP: itr%d: exceptions=%08x\n", + vecitr >> FPSCR_LENGTH_BIT, except); + + exceptions |= except; + + /* + * CHECK: It appears to be undefined whether we stop when + * we encounter an exception. We continue. + */ + dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7); + sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7); + if (FREG_BANK(sm) != 0) + sm = FREG_BANK(sm) + ((FREG_IDX(sm) + vecstride) & 7); + } + return exceptions; + +invalid: + return (u32)-1; +} diff --git a/src/core/core.cpp b/src/core/core.cpp index f21801e52..25c78d33c 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -3,20 +3,16 @@ // Refer to the license.txt file included. #include "common/common_types.h" -#include "common/log.h" -#include "common/symbols.h" - -#include "video_core/video_core.h" #include "core/core.h" -#include "core/mem_map.h" -#include "core/hw/hw.h" -#include "core/hw/gpu.h" + +#include "core/settings.h" #include "core/arm/disassembler/arm_disasm.h" #include "core/arm/interpreter/arm_interpreter.h" - +#include "core/arm/dyncom/arm_dyncom.h" #include "core/hle/hle.h" #include "core/hle/kernel/thread.h" +#include "core/hw/hw.h" namespace Core { @@ -54,9 +50,18 @@ int Init() { NOTICE_LOG(MASTER_LOG, "initialized OK"); g_disasm = new ARM_Disasm(); - g_app_core = new ARM_Interpreter(); g_sys_core = new ARM_Interpreter(); + switch (Settings::values.cpu_core) { + case CPU_FastInterpreter: + g_app_core = new ARM_DynCom(); + break; + case CPU_Interpreter: + default: + g_app_core = new ARM_Interpreter(); + break; + } + g_last_ticks = Core::g_app_core->GetTicks(); return 0; diff --git a/src/core/core.h b/src/core/core.h index 9c72c8b3f..850bb0ab4 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -5,12 +5,17 @@ #pragma once #include "core/arm/arm_interface.h" -#include "core/arm/interpreter/armdefs.h" +#include "core/arm/skyeye_common/armdefs.h" //////////////////////////////////////////////////////////////////////////////////////////////////// namespace Core { +enum CPUCore { + CPU_Interpreter, + CPU_FastInterpreter +}; + extern ARM_Interface* g_app_core; ///< ARM11 application core extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core @@ -21,13 +26,13 @@ void Start(); /** * Run the core CPU loop - * This function loops for 100 instructions in the CPU before trying to update hardware. This is a - * little bit faster than SingleStep, and should be pretty much equivalent. The number of - * instructions chosen is fairly arbitrary, however a large number will more drastically affect the - * frequency of GSP interrupts and likely break things. The point of this is to just loop in the CPU - * for more than 1 instruction to reduce overhead and make it a little bit faster... + * This function runs the core for the specified number of CPU instructions before trying to update + * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not + * required to do a full dispatch with each instruction. NOTE: the number of instructions requested + * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is + * requested (e.g. on a thread switch). */ -void RunLoop(int tight_loop=100); +void RunLoop(int tight_loop=1000); /// Step the CPU one instruction void SingleStep(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 25fccce76..0116cb376 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -7,11 +7,12 @@ #include <atomic> #include <mutex> -#include "common/msg_handler.h" #include "common/chunk_file.h" +#include "common/msg_handler.h" +#include "common/string_util.h" -#include "core/core_timing.h" #include "core/core.h" +#include "core/core_timing.h" int g_clock_rate_arm11 = 268123480; @@ -586,9 +587,10 @@ std::string GetScheduledEventsSummary() const char *name = event_types[ptr->type].name; if (!name) name = "[unknown]"; - char temp[512]; - sprintf(temp, "%s : %i %08x%08x\n", name, (int)ptr->time, (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); - text += temp; + + text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)ptr->time, + (u32)(ptr->userdata >> 32), (u32)(ptr->userdata)); + ptr = ptr->next; } return text; diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h index ac5630bea..38145eed8 100644 --- a/src/core/file_sys/archive.h +++ b/src/core/file_sys/archive.h @@ -4,8 +4,16 @@ #pragma once +#include <memory> + #include "common/common_types.h" +#include "common/string_util.h" +#include "common/bit_field.h" + +#include "core/file_sys/file.h" +#include "core/file_sys/directory.h" +#include "core/mem_map.h" #include "core/hle/kernel/kernel.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -13,6 +21,110 @@ namespace FileSys { +// Path string type +enum LowPathType : u32 { + Invalid = 0, + Empty = 1, + Binary = 2, + Char = 3, + Wchar = 4 +}; + +union Mode { + u32 hex; + BitField<0, 1, u32> read_flag; + BitField<1, 1, u32> write_flag; + BitField<2, 1, u32> create_flag; +}; + +class Path { +public: + + Path(): + type(Invalid) + { + } + + Path(LowPathType type, u32 size, u32 pointer): + type(type) + { + switch (type) { + case Binary: + { + u8* data = Memory::GetPointer(pointer); + binary = std::vector<u8>(data, data + size); + break; + } + case Char: + { + const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer)); + string = std::string(data, size - 1); // Data is always null-terminated. + break; + } + case Wchar: + { + const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer)); + u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated. + break; + } + } + } + + LowPathType GetType() const { + return type; + } + + const std::string AsString() const { + switch (GetType()) { + case Char: + return string; + case Wchar: + return Common::UTF16ToUTF8(u16str); + case Empty: + return {}; + default: + ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!"); + return {}; + } + } + + const std::u16string AsU16Str() const { + switch (GetType()) { + case Char: + return Common::UTF8ToUTF16(string); + case Wchar: + return u16str; + case Empty: + return {}; + default: + ERROR_LOG(KERNEL, "LowPathType cannot be converted to u16string!"); + return {}; + } + } + + const std::vector<u8> AsBinary() const { + switch (GetType()) { + case Binary: + return binary; + case Char: + return std::vector<u8>(string.begin(), string.end()); + case Wchar: + return std::vector<u8>(u16str.begin(), u16str.end()); + case Empty: + return {}; + default: + ERROR_LOG(KERNEL, "LowPathType cannot be converted to binary!"); + return {}; + } + } + +private: + LowPathType type; + std::vector<u8> binary; + std::string string; + std::u16string u16str; +}; + class Archive : NonCopyable { public: /// Supported archive types @@ -36,6 +148,28 @@ public: virtual IdCode GetIdCode() const = 0; /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ + virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0; + + /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ + virtual bool CreateDirectory(const std::string& path) const = 0; + + /** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ + virtual std::unique_ptr<Directory> OpenDirectory(const std::string& path) const = 0; + + /** * Read data from the archive * @param offset Offset in bytes to start reading data from * @param length Length in bytes of data to read from archive diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index dc3fb1807..cc759faa8 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -5,6 +5,8 @@ #include "common/common_types.h" #include "core/file_sys/archive_romfs.h" +#include "core/file_sys/directory_romfs.h" +#include "core/file_sys/file_romfs.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // FileSys namespace @@ -22,6 +24,35 @@ Archive_RomFS::~Archive_RomFS() { } /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ +std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mode mode) const { + return std::unique_ptr<File>(new File_RomFS); +} + +/** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ +bool Archive_RomFS::CreateDirectory(const std::string& path) const { + ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS."); + return false; +}; + +/** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ +std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path) const { + return std::unique_ptr<Directory>(new Directory_RomFS); +} + +/** * Read data from the archive * @param offset Offset in bytes to start reading data from * @param length Length in bytes of data to read from archive @@ -29,7 +60,7 @@ Archive_RomFS::~Archive_RomFS() { * @return Number of bytes read */ size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { - DEBUG_LOG(FILESYS, "called offset=%d, length=%d", offset, length); + DEBUG_LOG(FILESYS, "called offset=%llu, length=%d", offset, length); memcpy(buffer, &raw_data[(u32)offset], length); return length; } diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index e9ed6f77a..ae2344e82 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -29,6 +29,28 @@ public: IdCode GetIdCode() const override { return IdCode::RomFS; }; /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ + std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; + + /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ + bool CreateDirectory(const std::string& path) const override; + + /** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ + std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; + + /** * Read data from the archive * @param offset Offset in bytes to start reading data from * @param length Length in bytes of data to read from archive diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp new file mode 100644 index 000000000..66931e93e --- /dev/null +++ b/src/core/file_sys/archive_sdmc.cpp @@ -0,0 +1,129 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <sys/stat.h> + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/archive_sdmc.h" +#include "core/file_sys/directory_sdmc.h" +#include "core/file_sys/file_sdmc.h" +#include "core/settings.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +Archive_SDMC::Archive_SDMC(const std::string& mount_point) { + this->mount_point = mount_point; + DEBUG_LOG(FILESYS, "Directory %s set as SDMC.", mount_point.c_str()); +} + +Archive_SDMC::~Archive_SDMC() { +} + +/** + * Initialize the archive. + * @return true if it initialized successfully + */ +bool Archive_SDMC::Initialize() { + if (!Settings::values.use_virtual_sd) { + WARN_LOG(FILESYS, "SDMC disabled by config."); + return false; + } + + if (!FileUtil::CreateFullPath(mount_point)) { + WARN_LOG(FILESYS, "Unable to create SDMC path."); + return false; + } + + return true; +} + +/** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ +std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const { + DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.c_str(), mode); + File_SDMC* file = new File_SDMC(this, path, mode); + if (!file->Open()) + return nullptr; + return std::unique_ptr<File>(file); +} + +/** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ +bool Archive_SDMC::CreateDirectory(const std::string& path) const { + return FileUtil::CreateDir(GetMountPoint() + path); +} + +/** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ +std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const std::string& path) const { + DEBUG_LOG(FILESYS, "called path=%s", path.c_str()); + Directory_SDMC* directory = new Directory_SDMC(this, path); + return std::unique_ptr<Directory>(directory); +} + +/** + * Read data from the archive + * @param offset Offset in bytes to start reading archive from + * @param length Length in bytes to read data from archive + * @param buffer Buffer to read data into + * @return Number of bytes read + */ +size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { + ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); + return -1; +} + +/** + * Write data to the archive + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to archive + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ +size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { + ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); + return -1; +} + +/** + * Get the size of the archive in bytes + * @return Size of the archive in bytes + */ +size_t Archive_SDMC::GetSize() const { + ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); + return 0; +} + +/** + * Set the size of the archive in bytes + */ +void Archive_SDMC::SetSize(const u64 size) { + ERROR_LOG(FILESYS, "(UNIMPLEMENTED)"); +} + +/** + * Getter for the path used for this Archive + * @return Mount point of that passthrough archive + */ +std::string Archive_SDMC::GetMountPoint() const { + return mount_point; +} + +} // namespace FileSys diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h new file mode 100644 index 000000000..0e059b635 --- /dev/null +++ b/src/core/file_sys/archive_sdmc.h @@ -0,0 +1,97 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/file_sys/archive.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +/// File system interface to the SDMC archive +class Archive_SDMC final : public Archive { +public: + Archive_SDMC(const std::string& mount_point); + ~Archive_SDMC() override; + + /** + * Initialize the archive. + * @return true if it initialized successfully + */ + bool Initialize(); + + /** + * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) + * @return IdCode of the archive + */ + IdCode GetIdCode() const override { return IdCode::SDMC; }; + + /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ + std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; + + /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ + bool CreateDirectory(const std::string& path) const override; + + /** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ + std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; + + /** + * Read data from the archive + * @param offset Offset in bytes to start reading archive from + * @param length Length in bytes to read data from archive + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + size_t Read(const u64 offset, const u32 length, u8* buffer) const override; + + /** + * Write data to the archive + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to archive + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ + size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; + + /** + * Get the size of the archive in bytes + * @return Size of the archive in bytes + */ + size_t GetSize() const override; + + /** + * Set the size of the archive in bytes + */ + void SetSize(const u64 size) override; + + /** + * Getter for the path used for this Archive + * @return Mount point of that passthrough archive + */ + std::string GetMountPoint() const; + +private: + std::string mount_point; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h new file mode 100644 index 000000000..e10431337 --- /dev/null +++ b/src/core/file_sys/directory.h @@ -0,0 +1,59 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <cstddef> + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +// Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format +const size_t FILENAME_LENGTH = 0x20C / 2; +struct Entry { + char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) + std::array<char, 9> short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated) + char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) + std::array<char, 4> extension; // 8.3 file extension (set to spaces for directories, null-terminated) + char unknown2; // unknown (always 0x01) + char unknown3; // unknown (0x00 or 0x08) + char is_directory; // directory flag + char is_hidden; // hidden flag + char is_archive; // archive flag + char is_read_only; // read-only flag + u64 file_size; // file size (for files only) +}; +static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); +static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); +static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); +static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); +static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); + +class Directory : NonCopyable { +public: + Directory() { } + virtual ~Directory() { } + + /** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ + virtual u32 Read(const u32 count, Entry* entries) = 0; + + /** + * Close the directory + * @return true if the directory closed correctly + */ + virtual bool Close() const = 0; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/directory_romfs.cpp b/src/core/file_sys/directory_romfs.cpp new file mode 100644 index 000000000..4e8f4c04d --- /dev/null +++ b/src/core/file_sys/directory_romfs.cpp @@ -0,0 +1,38 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common_types.h" + +#include "core/file_sys/directory_romfs.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +Directory_RomFS::Directory_RomFS() { +} + +Directory_RomFS::~Directory_RomFS() { +} + +/** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ +u32 Directory_RomFS::Read(const u32 count, Entry* entries) { + return 0; +} + +/** + * Close the directory + * @return true if the directory closed correctly + */ +bool Directory_RomFS::Close() const { + return false; +} + +} // namespace FileSys diff --git a/src/core/file_sys/directory_romfs.h b/src/core/file_sys/directory_romfs.h new file mode 100644 index 000000000..4b71c4b13 --- /dev/null +++ b/src/core/file_sys/directory_romfs.h @@ -0,0 +1,37 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/file_sys/directory.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class Directory_RomFS final : public Directory { +public: + Directory_RomFS(); + ~Directory_RomFS() override; + + /** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ + u32 Read(const u32 count, Entry* entries) override; + + /** + * Close the directory + * @return true if the directory closed correctly + */ + bool Close() const override; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp new file mode 100644 index 000000000..fd558def9 --- /dev/null +++ b/src/core/file_sys/directory_sdmc.cpp @@ -0,0 +1,81 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <sys/stat.h> + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/directory_sdmc.h" +#include "core/file_sys/archive_sdmc.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const std::string& path) { + // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass + // the root directory we set while opening the archive. + // For example, opening /../../usr/bin can give the emulated program your installed programs. + std::string absolute_path = archive->GetMountPoint() + path; + FileUtil::ScanDirectoryTree(absolute_path, directory); + children_iterator = directory.children.begin(); +} + +Directory_SDMC::~Directory_SDMC() { + Close(); +} + +/** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ +u32 Directory_SDMC::Read(const u32 count, Entry* entries) { + u32 entries_read = 0; + + while (entries_read < count && children_iterator != directory.children.cend()) { + const FileUtil::FSTEntry& file = *children_iterator; + const std::string& filename = file.virtualName; + Entry& entry = entries[entries_read]; + + WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); + + // TODO(Link Mauve): use a proper conversion to UTF-16. + for (int j = 0; j < FILENAME_LENGTH; ++j) { + entry.filename[j] = filename[j]; + if (!filename[j]) + break; + } + + FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); + + entry.is_directory = file.isDirectory; + entry.is_hidden = (filename[0] == '.'); + entry.is_read_only = 0; + entry.file_size = file.size; + + // We emulate a SD card where the archive bit has never been cleared, as it would be on + // most user SD cards. + // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a + // file bit. + entry.is_archive = !file.isDirectory; + + ++entries_read; + ++children_iterator; + } + return entries_read; +} + +/** + * Close the directory + * @return true if the directory closed correctly + */ +bool Directory_SDMC::Close() const { + return true; +} + +} // namespace FileSys diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h new file mode 100644 index 000000000..cb8d32fda --- /dev/null +++ b/src/core/file_sys/directory_sdmc.h @@ -0,0 +1,48 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/directory.h" +#include "core/file_sys/archive_sdmc.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class Directory_SDMC final : public Directory { +public: + Directory_SDMC(); + Directory_SDMC(const Archive_SDMC* archive, const std::string& path); + ~Directory_SDMC() override; + + /** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ + u32 Read(const u32 count, Entry* entries) override; + + /** + * Close the directory + * @return true if the directory closed correctly + */ + bool Close() const override; + +private: + u32 total_entries_in_directory; + FileUtil::FSTEntry directory; + + // We need to remember the last entry we returned, so a subsequent call to Read will continue + // from the next one. This iterator will always point to the next unread entry. + std::vector<FileUtil::FSTEntry>::iterator children_iterator; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/file.h b/src/core/file_sys/file.h new file mode 100644 index 000000000..4013b6c3e --- /dev/null +++ b/src/core/file_sys/file.h @@ -0,0 +1,66 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class File : NonCopyable { +public: + File() { } + virtual ~File() { } + + /** + * Open the file + * @return true if the file opened correctly + */ + virtual bool Open() = 0; + + /** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; + + /** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param flush The flush parameters (0 == do not flush) + * @param buffer Buffer to read data from + * @return Number of bytes written + */ + virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; + + /** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ + virtual size_t GetSize() const = 0; + + /** + * Set the size of the file in bytes + * @param size New size of the file + * @return true if successful + */ + virtual bool SetSize(const u64 size) const = 0; + + /** + * Close the file + * @return true if the file closed correctly + */ + virtual bool Close() const = 0; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp new file mode 100644 index 000000000..b55708df4 --- /dev/null +++ b/src/core/file_sys/file_romfs.cpp @@ -0,0 +1,76 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common_types.h" + +#include "core/file_sys/file_romfs.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +File_RomFS::File_RomFS() { +} + +File_RomFS::~File_RomFS() { +} + +/** + * Open the file + * @return true if the file opened correctly + */ +bool File_RomFS::Open() { + return false; +} + +/** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ +size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { + return -1; +} + +/** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param flush The flush parameters (0 == do not flush) + * @param buffer Buffer to read data from + * @return Number of bytes written + */ +size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { + return -1; +} + +/** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ +size_t File_RomFS::GetSize() const { + return -1; +} + +/** + * Set the size of the file in bytes + * @param size New size of the file + * @return true if successful + */ +bool File_RomFS::SetSize(const u64 size) const { + return false; +} + +/** + * Close the file + * @return true if the file closed correctly + */ +bool File_RomFS::Close() const { + return false; +} + +} // namespace FileSys diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h new file mode 100644 index 000000000..5196701d3 --- /dev/null +++ b/src/core/file_sys/file_romfs.h @@ -0,0 +1,67 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/file_sys/file.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class File_RomFS final : public File { +public: + File_RomFS(); + ~File_RomFS() override; + + /** + * Open the file + * @return true if the file opened correctly + */ + bool Open() override; + + /** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + size_t Read(const u64 offset, const u32 length, u8* buffer) const override; + + /** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param flush The flush parameters (0 == do not flush) + * @param buffer Buffer to read data from + * @return Number of bytes written + */ + size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; + + /** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ + size_t GetSize() const override; + + /** + * Set the size of the file in bytes + * @param size New size of the file + * @return true if successful + */ + bool SetSize(const u64 size) const override; + + /** + * Close the file + * @return true if the file closed correctly + */ + bool Close() const override; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp new file mode 100644 index 000000000..26204392c --- /dev/null +++ b/src/core/file_sys/file_sdmc.cpp @@ -0,0 +1,107 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <sys/stat.h> + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/file_sdmc.h" +#include "core/file_sys/archive_sdmc.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +File_SDMC::File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode) { + // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass + // the root directory we set while opening the archive. + // For example, opening /../../etc/passwd can give the emulated program your users list. + this->path = archive->GetMountPoint() + path; + this->mode.hex = mode.hex; +} + +File_SDMC::~File_SDMC() { + Close(); +} + +/** + * Open the file + * @return true if the file opened correctly + */ +bool File_SDMC::Open() { + if (!mode.create_flag && !FileUtil::Exists(path)) { + ERROR_LOG(FILESYS, "Non-existing file %s can’t be open without mode create.", path.c_str()); + return false; + } + + std::string mode_string; + if (mode.read_flag && mode.write_flag) + mode_string = "w+"; + else if (mode.read_flag) + mode_string = "r"; + else if (mode.write_flag) + mode_string = "w"; + + file = new FileUtil::IOFile(path, mode_string.c_str()); + return true; +} + +/** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ +size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { + file->Seek(offset, SEEK_SET); + return file->ReadBytes(buffer, length); +} + +/** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param flush The flush parameters (0 == do not flush) + * @param buffer Buffer to read data from + * @return Number of bytes written + */ +size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { + file->Seek(offset, SEEK_SET); + size_t written = file->WriteBytes(buffer, length); + if (flush) + file->Flush(); + return written; +} + +/** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ +size_t File_SDMC::GetSize() const { + return static_cast<size_t>(file->GetSize()); +} + +/** + * Set the size of the file in bytes + * @param size New size of the file + * @return true if successful + */ +bool File_SDMC::SetSize(const u64 size) const { + file->Resize(size); + file->Flush(); + return true; +} + +/** + * Close the file + * @return true if the file closed correctly + */ +bool File_SDMC::Close() const { + return file->Close(); +} + +} // namespace FileSys diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h new file mode 100644 index 000000000..df032f7c0 --- /dev/null +++ b/src/core/file_sys/file_sdmc.h @@ -0,0 +1,75 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/file_sys/file.h" +#include "core/file_sys/archive_sdmc.h" +#include "core/loader/loader.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class File_SDMC final : public File { +public: + File_SDMC(); + File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode); + ~File_SDMC() override; + + /** + * Open the file + * @return true if the file opened correctly + */ + bool Open() override; + + /** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + size_t Read(const u64 offset, const u32 length, u8* buffer) const override; + + /** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param flush The flush parameters (0 == do not flush) + * @param buffer Buffer to read data from + * @return Number of bytes written + */ + size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; + + /** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ + size_t GetSize() const override; + + /** + * Set the size of the file in bytes + * @param size New size of the file + * @return true if successful + */ + bool SetSize(const u64 size) const override; + + /** + * Close the file + * @return true if the file closed correctly + */ + bool Close() const override; + +private: + std::string path; + Mode mode; + FileUtil::IOFile* file; +}; + +} // namespace FileSys diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp index 8c898b265..a45e61427 100644 --- a/src/core/hle/config_mem.cpp +++ b/src/core/hle/config_mem.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include "common/common_types.h" -#include "common/log.h" #include "core/hle/config_mem.h" diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp index 9a5b0deda..1eb33eb86 100644 --- a/src/core/hle/coprocessor.cpp +++ b/src/core/hle/coprocessor.cpp @@ -5,7 +5,6 @@ #include "core/hle/coprocessor.h" #include "core/hle/hle.h" #include "core/mem_map.h" -#include "core/core.h" namespace HLE { diff --git a/src/core/hle/coprocessor.h b/src/core/hle/coprocessor.h deleted file mode 100644 index b08d6f3ee..000000000 --- a/src/core/hle/coprocessor.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -namespace HLE { - -/// Coprocessor operations -enum CoprocessorOperation { - DATA_SYNCHRONIZATION_BARRIER = 0xE0, - CALL_GET_THREAD_COMMAND_BUFFER = 0xE1, -}; - -/// Call an MRC (move to ARM register from coprocessor) instruction in HLE -s32 CallMRC(u32 instruction); - -} // namespace diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 53cda4a61..b03894ad7 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -6,7 +6,6 @@ #include "core/mem_map.h" #include "core/hle/hle.h" -#include "core/hle/svc.h" #include "core/hle/kernel/thread.h" #include "core/hle/service/service.h" diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 174d4cd6e..2b21657da 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp @@ -17,11 +17,11 @@ namespace Kernel { class AddressArbiter : public Object { public: - std::string GetTypeName() const { return "Arbiter"; } - std::string GetName() const { return name; } + std::string GetTypeName() const override { return "Arbiter"; } + std::string GetName() const override { return name; } static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; } - Kernel::HandleType GetHandleType() const { return HandleType::AddressArbiter; } + Kernel::HandleType GetHandleType() const override { return HandleType::AddressArbiter; } std::string name; ///< Name of address arbiter object (optional) @@ -30,7 +30,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); return 0; diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp index 1596367c3..764082d71 100644 --- a/src/core/hle/kernel/archive.cpp +++ b/src/core/hle/kernel/archive.cpp @@ -3,11 +3,13 @@ // Refer to the license.txt file included. #include "common/common_types.h" +#include "common/file_util.h" #include "common/math_util.h" #include "core/file_sys/archive.h" +#include "core/file_sys/archive_sdmc.h" +#include "core/file_sys/directory.h" #include "core/hle/service/service.h" -#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/archive.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -30,13 +32,21 @@ enum class FileCommand : u32 { Flush = 0x08090000, }; +// Command to access directory +enum class DirectoryCommand : u32 { + Dummy1 = 0x000100C6, + Control = 0x040100C4, + Read = 0x08010042, + Close = 0x08020000, +}; + class Archive : public Object { public: - std::string GetTypeName() const { return "Archive"; } - std::string GetName() const { return name; } + std::string GetTypeName() const override { return "Archive"; } + std::string GetName() const override { return name; } static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; } - Kernel::HandleType GetHandleType() const { return HandleType::Archive; } + Kernel::HandleType GetHandleType() const override { return HandleType::Archive; } std::string name; ///< Name of archive (optional) FileSys::Archive* backend; ///< Archive backend interface @@ -46,7 +56,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result SyncRequest(bool* wait) { + Result SyncRequest(bool* wait) override { u32* cmd_buff = Service::GetCommandBuffer(); FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); @@ -86,6 +96,13 @@ public: backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); break; } + case FileCommand::Close: + { + DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + Kernel::g_object_pool.Destroy<Archive>(GetHandle()); + CloseArchive(backend->GetIdCode()); + break; + } // Unknown command... default: { @@ -102,7 +119,162 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { + // TODO(bunnei): ImplementMe + ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); + return 0; + } +}; + +class File : public Object { +public: + std::string GetTypeName() const override { return "File"; } + std::string GetName() const override { return path; } + + static Kernel::HandleType GetStaticHandleType() { return HandleType::File; } + Kernel::HandleType GetHandleType() const override { return HandleType::File; } + + std::string path; ///< Path of the file + std::unique_ptr<FileSys::File> backend; ///< File backend interface + + /** + * Synchronize kernel object + * @param wait Boolean wait set if current thread should wait as a result of sync operation + * @return Result of operation, 0 on success, otherwise error code + */ + Result SyncRequest(bool* wait) override { + u32* cmd_buff = Service::GetCommandBuffer(); + FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); + switch (cmd) { + + // Read from file... + case FileCommand::Read: + { + u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; + u32 length = cmd_buff[3]; + u32 address = cmd_buff[5]; + DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%llx length=%d address=0x%x", + GetTypeName().c_str(), GetName().c_str(), offset, length, address); + cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); + break; + } + + // Write to file... + case FileCommand::Write: + { + u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; + u32 length = cmd_buff[3]; + u32 flush = cmd_buff[4]; + u32 address = cmd_buff[6]; + DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", + GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); + cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); + break; + } + + case FileCommand::GetSize: + { + DEBUG_LOG(KERNEL, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str()); + u64 size = backend->GetSize(); + cmd_buff[2] = (u32)size; + cmd_buff[3] = size >> 32; + break; + } + + case FileCommand::SetSize: + { + u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); + DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); + backend->SetSize(size); + break; + } + + case FileCommand::Close: + { + DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + Kernel::g_object_pool.Destroy<File>(GetHandle()); + break; + } + + // Unknown command... + default: + ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); + cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. + return -1; + } + cmd_buff[1] = 0; // No error + return 0; + } + + /** + * Wait for kernel object to synchronize + * @param wait Boolean wait set if current thread should wait as a result of sync operation + * @return Result of operation, 0 on success, otherwise error code + */ + Result WaitSynchronization(bool* wait) override { + // TODO(bunnei): ImplementMe + ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); + return 0; + } +}; + +class Directory : public Object { +public: + std::string GetTypeName() const override { return "Directory"; } + std::string GetName() const override { return path; } + + static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; } + Kernel::HandleType GetHandleType() const override { return HandleType::Directory; } + + std::string path; ///< Path of the directory + std::unique_ptr<FileSys::Directory> backend; ///< File backend interface + + /** + * Synchronize kernel object + * @param wait Boolean wait set if current thread should wait as a result of sync operation + * @return Result of operation, 0 on success, otherwise error code + */ + Result SyncRequest(bool* wait) override { + u32* cmd_buff = Service::GetCommandBuffer(); + DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); + switch (cmd) { + + // Read from directory... + case DirectoryCommand::Read: + { + u32 count = cmd_buff[1]; + u32 address = cmd_buff[3]; + FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); + DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); + + // Number of entries actually read + cmd_buff[2] = backend->Read(count, entries); + break; + } + + case DirectoryCommand::Close: + { + DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + Kernel::g_object_pool.Destroy<Directory>(GetHandle()); + break; + } + + // Unknown command... + default: + ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); + cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. + return -1; + } + cmd_buff[1] = 0; // No error + return 0; + } + + /** + * Wait for kernel object to synchronize + * @param wait Boolean wait set if current thread should wait as a result of sync operation + * @return Result of operation, 0 on success, otherwise error code + */ + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); return 0; @@ -127,6 +299,21 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code) { } /** + * Closes an archive + * @param id_code IdCode of the archive to open + * @return Result of operation, 0 on success, otherwise error code + */ +Result CloseArchive(FileSys::Archive::IdCode id_code) { + if (1 != g_archive_map.erase(id_code)) { + ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code); + return -1; + } + + INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); + return 0; +} + +/** * Mounts an archive * @param archive Pointer to the archive to mount * @return Result of operation, 0 on success, otherwise error code @@ -172,9 +359,73 @@ Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { return handle; } +/** + * Open a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @param mode Mode under which to open the File + * @return Opened File object + */ +Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) { + File* file = new File; + Handle handle = Kernel::g_object_pool.Create(file); + + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + file->path = path; + file->backend = archive->backend->OpenFile(path, mode); + + if (!file->backend) + return 0; + + return handle; +} + +/** + * Create a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Opened Directory object + */ +Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) { + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + if (archive == nullptr) + return -1; + if (archive->backend->CreateDirectory(path)) + return 0; + return -1; +} + +/** + * Open a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Opened Directory object + */ +Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) { + Directory* directory = new Directory; + Handle handle = Kernel::g_object_pool.Create(directory); + + Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); + directory->path = path; + directory->backend = archive->backend->OpenDirectory(path); + + return handle; +} + /// Initialize archives void ArchiveInit() { g_archive_map.clear(); + + // TODO(Link Mauve): Add the other archive types (see here for the known types: + // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished + // archive type is SDMC, so it is the only one getting exposed. + + std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); + auto archive = new FileSys::Archive_SDMC(sdmc_directory); + if (archive->Initialize()) + CreateArchive(archive, "SDMC"); + else + ERROR_LOG(KERNEL, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); } /// Shutdown archives diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h index 3758e7061..0230996b6 100644 --- a/src/core/hle/kernel/archive.h +++ b/src/core/hle/kernel/archive.h @@ -22,6 +22,13 @@ namespace Kernel { Handle OpenArchive(FileSys::Archive::IdCode id_code); /** + * Closes an archive + * @param id_code IdCode of the archive to open + * @return true if it worked fine + */ +Result CloseArchive(FileSys::Archive::IdCode id_code); + +/** * Creates an Archive * @param backend File system backend interface to the archive * @param name Optional name of Archive @@ -29,6 +36,31 @@ Handle OpenArchive(FileSys::Archive::IdCode id_code); */ Handle CreateArchive(FileSys::Archive* backend, const std::string& name); +/** + * Open a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @param mode Mode under which to open the File + * @return Opened File object + */ +Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode); + +/** + * Create a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether creation of directory succeeded + */ +Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name); + +/** + * Open a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Opened Directory object + */ +Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name); + /// Initialize archives void ArchiveInit(); diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index 64f6a9649..45ed79be8 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -16,11 +16,11 @@ namespace Kernel { class Event : public Object { public: - std::string GetTypeName() const { return "Event"; } - std::string GetName() const { return name; } + std::string GetTypeName() const override { return "Event"; } + std::string GetName() const override { return name; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Event; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Event; } ResetType intitial_reset_type; ///< ResetType specified at Event initialization ResetType reset_type; ///< Current ResetType @@ -35,7 +35,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { *wait = locked; if (locked) { Handle thread = GetCurrentThreadHandle(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index a4a258875..88cbc1af5 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include <string.h> - #include "common/common.h" #include "core/core.h" @@ -87,47 +85,8 @@ int ObjectPool::GetCount() { } Object* ObjectPool::CreateByIDType(int type) { - // Used for save states. This is ugly, but what other way is there? - switch (type) { - //case SCE_KERNEL_TMID_Alarm: - // return __KernelAlarmObject(); - //case SCE_KERNEL_TMID_EventFlag: - // return __KernelEventFlagObject(); - //case SCE_KERNEL_TMID_Mbox: - // return __KernelMbxObject(); - //case SCE_KERNEL_TMID_Fpl: - // return __KernelMemoryFPLObject(); - //case SCE_KERNEL_TMID_Vpl: - // return __KernelMemoryVPLObject(); - //case PPSSPP_KERNEL_TMID_PMB: - // return __KernelMemoryPMBObject(); - //case PPSSPP_KERNEL_TMID_Module: - // return __KernelModuleObject(); - //case SCE_KERNEL_TMID_Mpipe: - // return __KernelMsgPipeObject(); - //case SCE_KERNEL_TMID_Mutex: - // return __KernelMutexObject(); - //case SCE_KERNEL_TMID_LwMutex: - // return __KernelLwMutexObject(); - //case SCE_KERNEL_TMID_Semaphore: - // return __KernelSemaphoreObject(); - //case SCE_KERNEL_TMID_Callback: - // return __KernelCallbackObject(); - //case SCE_KERNEL_TMID_Thread: - // return __KernelThreadObject(); - //case SCE_KERNEL_TMID_VTimer: - // return __KernelVTimerObject(); - //case SCE_KERNEL_TMID_Tlspl: - // return __KernelTlsplObject(); - //case PPSSPP_KERNEL_TMID_File: - // return __KernelFileNodeObject(); - //case PPSSPP_KERNEL_TMID_DirList: - // return __KernelDirListingObject(); - - default: - ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type); - return nullptr; - } + ERROR_LOG(COMMON, "Unimplemented: %d.", type); + return nullptr; } /// Initialize the kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 0e7e5ff68..867d1b89c 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -32,6 +32,7 @@ enum class HandleType : u32 { File = 10, Semaphore = 11, Archive = 12, + Directory = 13, }; enum { diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 5d7d65dd9..fcfd061ac 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -15,11 +15,11 @@ namespace Kernel { class Mutex : public Object { public: - std::string GetTypeName() const { return "Mutex"; } - std::string GetName() const { return name; } + std::string GetTypeName() const override { return "Mutex"; } + std::string GetName() const override { return name; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; } bool initial_locked; ///< Initial lock state when mutex was created bool locked; ///< Current locked state @@ -32,7 +32,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result SyncRequest(bool* wait) { + Result SyncRequest(bool* wait) override { // TODO(bunnei): ImplementMe locked = true; return 0; @@ -43,7 +43,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe *wait = locked; diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index 2a6a483a1..6bd5e2728 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -11,17 +11,17 @@ namespace Kernel { class SharedMemory : public Object { public: - std::string GetTypeName() const { return "SharedMemory"; } + std::string GetTypeName() const override { return "SharedMemory"; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::SharedMemory; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } /** * Wait for kernel object to synchronize * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); return 0; diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 8bd9ca1a1..e15590c49 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -3,10 +3,8 @@ // Refer to the license.txt file included. #include <algorithm> -#include <cstdio> #include <list> #include <map> -#include <string> #include <vector> #include "common/common.h" @@ -15,7 +13,6 @@ #include "core/core.h" #include "core/mem_map.h" #include "core/hle/hle.h" -#include "core/hle/svc.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" @@ -24,11 +21,11 @@ namespace Kernel { class Thread : public Kernel::Object { public: - std::string GetName() const { return name; } - std::string GetTypeName() const { return "Thread"; } + std::string GetName() const override { return name; } + std::string GetTypeName() const override { return "Thread"; } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Thread; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; } inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } @@ -41,7 +38,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { if (status != THREADSTATUS_DORMANT) { Handle thread = GetCurrentThreadHandle(); if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp new file mode 100644 index 000000000..b39603bdf --- /dev/null +++ b/src/core/hle/service/ac_u.cpp @@ -0,0 +1,44 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ac_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace AC_U + +namespace AC_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "CreateDefaultConfig"}, + {0x00040006, nullptr, "ConnectAsync"}, + {0x00050002, nullptr, "GetConnectResult"}, + {0x00080004, nullptr, "CloseAsync"}, + {0x00090002, nullptr, "GetCloseResult"}, + {0x000A0000, nullptr, "GetLastErrorCode"}, + {0x000D0000, nullptr, "GetWifiStatus"}, + {0x000E0042, nullptr, "GetCurrentAPInfo"}, + {0x00100042, nullptr, "GetCurrentNZoneInfo"}, + {0x00110042, nullptr, "GetNZoneApNumService"}, + {0x00240042, nullptr, "AddDenyApType "}, + {0x00270002, nullptr, "GetInfraPriority "}, + {0x002D0082, nullptr, "SetRequestEulaVersion"}, + {0x00300004, nullptr, "RegisterDisconnectEvent"}, + {0x003C0042, nullptr, "GetAPSSIDList"}, + {0x003E0042, nullptr, "IsConnected "}, + {0x00400042, nullptr, "SetClientVersion"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/hid.h b/src/core/hle/service/ac_u.h index b17fcfa86..3c5958d27 100644 --- a/src/core/hle/service/hid.h +++ b/src/core/hle/service/ac_u.h @@ -7,28 +7,23 @@ #include "core/hle/service/service.h" //////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_User +// Namespace AC_U -// This service is used for interfacing to physical user controls... perhaps "Human Interface -// Devices"? Uses include game pad controls, accelerometers, gyroscopes, etc. +// socket service "ac:u" -namespace HID_User { +namespace AC_U { class Interface : public Service::Interface { public: - Interface(); - ~Interface(); - /** * Gets the string port name used by CTROS for the service * @return Port name of service */ std::string GetPortName() const { - return "hid:USER"; + return "ac:u"; } - }; } // namespace diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt_u.cpp index e97e7dbf7..4f41ec5f4 100644 --- a/src/core/hle/service/apt.cpp +++ b/src/core/hle/service/apt_u.cpp @@ -8,13 +8,15 @@ #include "core/hle/hle.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/mutex.h" -#include "core/hle/service/apt.h" +#include "apt_u.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace APT_U namespace APT_U { +static Handle lock_handle = 0; + /// Signals used by APT functions enum class SignalType : u32 { None = 0x0, @@ -32,15 +34,32 @@ void Initialize(Service::Interface* self) { Kernel::SetEventLocked(cmd_buff[3], true); Kernel::SetEventLocked(cmd_buff[4], false); // Fire start event + _assert_msg_(KERNEL, (0 != lock_handle), "Cannot initialize without lock"); + Kernel::ReleaseMutex(lock_handle); + cmd_buff[1] = 0; // No error + DEBUG_LOG(KERNEL, "called"); } void GetLockHandle(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field + + if (0 == lock_handle) { + // TODO(bunnei): Verify if this is created here or at application boot? + lock_handle = Kernel::CreateMutex(false, "APT_U:Lock"); + Kernel::ReleaseMutex(lock_handle); + } cmd_buff[1] = 0; // No error - cmd_buff[5] = Kernel::CreateMutex(false, "APT_U:Lock"); + + // Not sure what these parameters are used for, but retail apps check that they are 0 after + // GetLockHandle has been called. + cmd_buff[2] = 0; + cmd_buff[3] = 0; + cmd_buff[4] = 0; + + cmd_buff[5] = lock_handle; DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]); } @@ -59,6 +78,25 @@ void InquireNotification(Service::Interface* self) { WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id); } +/** + * APT_U::ReceiveParameter service function. This returns the current parameter data from NS state, + * from the source process which set the parameters. Once finished, NS will clear a flag in the NS + * state so that this command will return an error if this command is used again if parameters were + * not set again. This is called when the second Initialize event is triggered. It returns a signal + * type indicating why it was triggered. + * Inputs: + * 1 : AppID + * 2 : Parameter buffer size, max size is 0x1000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unknown, for now assume AppID of the process which sent these parameters + * 3 : Unknown, for now assume Signal type + * 4 : Actual parameter buffer size, this is <= to the the input size + * 5 : Value + * 6 : Handle from the source process which set the parameters, likely used for shared memory + * 7 : Size + * 8 : Output parameter buffer ptr + */ void ReceiveParameter(Service::Interface* self) { u32* cmd_buff = Service::GetCommandBuffer(); u32 app_id = cmd_buff[1]; @@ -66,13 +104,74 @@ void ReceiveParameter(Service::Interface* self) { cmd_buff[1] = 0; // No error cmd_buff[2] = 0; cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type - cmd_buff[4] = 0x10; + cmd_buff[4] = 0x10; // Parameter buffer size (16) cmd_buff[5] = 0; cmd_buff[6] = 0; cmd_buff[7] = 0; WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); } +/** + * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter + * (except for the word value prior to the output handle), except this will not clear the flag + * (except when responseword[3]==8 || responseword[3]==9) in NS state. + * Inputs: + * 1 : AppID + * 2 : Parameter buffer size, max size is 0x1000 + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unknown, for now assume AppID of the process which sent these parameters + * 3 : Unknown, for now assume Signal type + * 4 : Actual parameter buffer size, this is <= to the the input size + * 5 : Value + * 6 : Handle from the source process which set the parameters, likely used for shared memory + * 7 : Size + * 8 : Output parameter buffer ptr + */ +void GlanceParameter(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + u32 app_id = cmd_buff[1]; + u32 buffer_size = cmd_buff[2]; + + cmd_buff[1] = 0; // No error + cmd_buff[2] = 0; + cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type + cmd_buff[4] = 0x10; // Parameter buffer size (16) + cmd_buff[5] = 0; + cmd_buff[6] = 0; + cmd_buff[7] = 0; + + WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); +} + +/** + * APT_U::AppletUtility service function + * Inputs: + * 1 : Unknown, but clearly used for something + * 2 : Buffer 1 size (purpose is unknown) + * 3 : Buffer 2 size (purpose is unknown) + * 5 : Buffer 1 address (purpose is unknown) + * 65 : Buffer 2 address (purpose is unknown) + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void AppletUtility(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // These are from 3dbrew - I'm not really sure what they're used for. + u32 unk = cmd_buff[1]; + u32 buffer1_size = cmd_buff[2]; + u32 buffer2_size = cmd_buff[3]; + u32 buffer1_addr = cmd_buff[5]; + u32 buffer2_addr = cmd_buff[65]; + + cmd_buff[1] = 0; // No error + + WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " + "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, + buffer1_addr, buffer2_addr); +} + const Interface::FunctionInfo FunctionTable[] = { {0x00010040, GetLockHandle, "GetLockHandle"}, {0x00020080, Initialize, "Initialize"}, @@ -87,7 +186,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000B0040, InquireNotification, "InquireNotification"}, {0x000C0104, nullptr, "SendParameter"}, {0x000D0080, ReceiveParameter, "ReceiveParameter"}, - {0x000E0080, nullptr, "GlanceParameter"}, + {0x000E0080, GlanceParameter, "GlanceParameter"}, {0x000F0100, nullptr, "CancelParameter"}, {0x001000C2, nullptr, "DebugFunc"}, {0x001100C0, nullptr, "MapProgramIdForDebug"}, @@ -148,10 +247,12 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00480100, nullptr, "GetProgramInfo"}, {0x00490180, nullptr, "Reboot"}, {0x004A0040, nullptr, "GetCaptureInfo"}, - {0x004B00C2, nullptr, "AppletUtility"}, + {0x004B00C2, AppletUtility, "AppletUtility"}, {0x004C0000, nullptr, "SetFatalErrDispMode"}, {0x004D0080, nullptr, "GetAppletProgramInfo"}, {0x004E0000, nullptr, "HardwareResetAsync"}, + {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"}, + {0x00500040, nullptr, "GetApplicationCpuTimeLimit"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -159,6 +260,8 @@ const Interface::FunctionInfo FunctionTable[] = { Interface::Interface() { Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + + lock_handle = 0; } Interface::~Interface() { diff --git a/src/core/hle/service/apt.h b/src/core/hle/service/apt_u.h index 4c7dd07e7..5af39e085 100644 --- a/src/core/hle/service/apt.h +++ b/src/core/hle/service/apt_u.h @@ -29,7 +29,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "APT:U"; } }; diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp new file mode 100644 index 000000000..822b0e2b8 --- /dev/null +++ b/src/core/hle/service/cfg_u.cpp @@ -0,0 +1,36 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/cfg_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CFG_U + +namespace CFG_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010082, nullptr, "GetConfigInfoBlk2"}, + {0x00020000, nullptr, "SecureInfoGetRegion"}, + {0x00030000, nullptr, "GenHashConsoleUnique"}, + {0x00040000, nullptr, "GetRegionCanadaUSA"}, + {0x00050000, nullptr, "GetSystemModel"}, + {0x00060000, nullptr, "GetModelNintendo2DS"}, + {0x00070040, nullptr, "unknown"}, + {0x00080080, nullptr, "unknown"}, + {0x00090080, nullptr, "GetCountryCodeString"}, + {0x000A0040, nullptr, "GetCountryCodeID"}, +}; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/cfg_u.h b/src/core/hle/service/cfg_u.h new file mode 100644 index 000000000..7525bd7c6 --- /dev/null +++ b/src/core/hle/service/cfg_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace CFG_U + +namespace CFG_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "cfg:u"; + } +}; + +} // namespace diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp new file mode 100644 index 000000000..9e84ac938 --- /dev/null +++ b/src/core/hle/service/dsp_dsp.cpp @@ -0,0 +1,52 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/dsp_dsp.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace DSP_DSP + +namespace DSP_DSP { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, nullptr, "RecvData"}, + {0x00020040, nullptr, "RecvDataIsReady"}, + {0x00030080, nullptr, "SendData"}, + {0x00040040, nullptr, "SendDataIsEmpty"}, + {0x00070040, nullptr, "WriteReg0x10"}, + {0x00080000, nullptr, "GetSemaphore"}, + {0x00090040, nullptr, "ClearSemaphore"}, + {0x000B0000, nullptr, "CheckSemaphoreRequest"}, + {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"}, + {0x000D0082, nullptr, "WriteProcessPipe"}, + {0x001000C0, nullptr, "ReadPipeIfPossible"}, + {0x001100C2, nullptr, "LoadComponent"}, + {0x00120000, nullptr, "UnloadComponent"}, + {0x00130082, nullptr, "FlushDataCache"}, + {0x00140082, nullptr, "InvalidateDCache "}, + {0x00150082, nullptr, "RegisterInterruptEvents"}, + {0x00160000, nullptr, "GetSemaphoreEventHandle"}, + {0x00170040, nullptr, "SetSemaphoreMask"}, + {0x00180040, nullptr, "GetPhysicalAddress"}, + {0x00190040, nullptr, "GetVirtualAddress" }, + {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, + {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, + {0x001C0082, nullptr, "SetIirFilterEQ"}, + {0x001F0000, nullptr, "GetHeadphoneStatus"}, + {0x00210000, nullptr, "GetIsDspOccupied"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h new file mode 100644 index 000000000..c439ed266 --- /dev/null +++ b/src/core/hle/service/dsp_dsp.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace DSP_DSP + +namespace DSP_DSP { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "dsp:DSP"; + } +}; + +} // namespace diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp new file mode 100644 index 000000000..917b2f8ca --- /dev/null +++ b/src/core/hle/service/err_f.cpp @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/err_f.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace ERR_F + +namespace ERR_F { + + const Interface::FunctionInfo FunctionTable[] = { + {0x00010800, nullptr, "ThrowFatalError"} + }; + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Interface class + + Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + } + + Interface::~Interface() { + } + +} // namespace diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h new file mode 100644 index 000000000..5da663267 --- /dev/null +++ b/src/core/hle/service/err_f.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace ERR_F + +namespace ERR_F { + + class Interface : public Service::Interface { + public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "err:f"; + } + }; + +} // namespace diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd_u.cpp new file mode 100644 index 000000000..58023e536 --- /dev/null +++ b/src/core/hle/service/frd_u.cpp @@ -0,0 +1,35 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/frd_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace FRD_U + +namespace FRD_U { + + const Interface::FunctionInfo FunctionTable[] = { + {0x00050000, nullptr, "GetFriendKey"}, + {0x00080000, nullptr, "GetMyPresence"}, + {0x00100040, nullptr, "GetPassword"}, + {0x00190042, nullptr, "GetFriendFavoriteGame"}, + {0x001A00C4, nullptr, "GetFriendInfo"}, + {0x001B0080, nullptr, "IsOnFriendList"}, + {0x001C0042, nullptr, "DecodeLocalFriendCode"}, + {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, + {0x00320042, nullptr, "SetClientSdkVersion"} + }; + //////////////////////////////////////////////////////////////////////////////////////////////////// + // Interface class + + Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); + } + + Interface::~Interface() { + } + +} // namespace diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h new file mode 100644 index 000000000..9df8a815a --- /dev/null +++ b/src/core/hle/service/frd_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace FRD_U + +namespace FRD_U { + + class Interface : public Service::Interface { + public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "frd:u"; + } + }; + +} // namespace diff --git a/src/core/hle/service/fs.cpp b/src/core/hle/service/fs.cpp deleted file mode 100644 index 5eabf36ad..000000000 --- a/src/core/hle/service/fs.cpp +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common/common.h" - -#include "core/loader/loader.h" -#include "core/hle/hle.h" -#include "core/hle/service/fs.h" -#include "core/hle/kernel/archive.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FS_User - -namespace FS_User { - -void Initialize(Service::Interface* self) { - u32* cmd_buff = Service::GetCommandBuffer(); - cmd_buff[1] = 0; // No error - DEBUG_LOG(KERNEL, "called"); -} - -void OpenFileDirectly(Service::Interface* self) { - u32* cmd_buff = Service::GetCommandBuffer(); - - FileSys::Archive::IdCode arch_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); - - // TODO(bunnei): Properly implement use of these... - //u32 transaction = cmd_buff[1]; - //u32 arch_lowpath_type = cmd_buff[3]; - //u32 arch_lowpath_sz = cmd_buff[4]; - //u32 file_lowpath_type = cmd_buff[5]; - //u32 file_lowpath_sz = cmd_buff[6]; - //u32 flags = cmd_buff[7]; - //u32 attr = cmd_buff[8]; - //u32 arch_lowpath_desc = cmd_buff[9]; - //u32 arch_lowpath_ptr = cmd_buff[10]; - //u32 file_lowpath_desc = cmd_buff[11]; - //u32 file_lowpath_ptr = cmd_buff[12]; - - Handle handle = Kernel::OpenArchive(arch_id); - if (0 != handle) { - cmd_buff[1] = 0; // No error - cmd_buff[3] = handle; - } - DEBUG_LOG(KERNEL, "called"); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x000100C6, nullptr, "Dummy1"}, - {0x040100C4, nullptr, "Control"}, - {0x08010002, Initialize, "Initialize"}, - {0x080201C2, nullptr, "OpenFile"}, - {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, - {0x08040142, nullptr, "DeleteFile"}, - {0x08050244, nullptr, "RenameFile"}, - {0x08060142, nullptr, "DeleteDirectory"}, - {0x08070142, nullptr, "DeleteDirectoryRecursively"}, - {0x08080202, nullptr, "CreateFile"}, - {0x08090182, nullptr, "CreateDirectory"}, - {0x080A0244, nullptr, "RenameDirectory"}, - {0x080B0102, nullptr, "OpenDirectory"}, - {0x080C00C2, nullptr, "OpenArchive"}, - {0x080D0144, nullptr, "ControlArchive"}, - {0x080E0080, nullptr, "CloseArchive"}, - {0x080F0180, nullptr, "FormatThisUserSaveData"}, - {0x08100200, nullptr, "CreateSystemSaveData"}, - {0x08110040, nullptr, "DeleteSystemSaveData"}, - {0x08120080, nullptr, "GetFreeBytes"}, - {0x08130000, nullptr, "GetCardType"}, - {0x08140000, nullptr, "GetSdmcArchiveResource"}, - {0x08150000, nullptr, "GetNandArchiveResource"}, - {0x08160000, nullptr, "GetSdmcFatfsErro"}, - {0x08170000, nullptr, "IsSdmcDetected"}, - {0x08180000, nullptr, "IsSdmcWritable"}, - {0x08190042, nullptr, "GetSdmcCid"}, - {0x081A0042, nullptr, "GetNandCid"}, - {0x081B0000, nullptr, "GetSdmcSpeedInfo"}, - {0x081C0000, nullptr, "GetNandSpeedInfo"}, - {0x081D0042, nullptr, "GetSdmcLog"}, - {0x081E0042, nullptr, "GetNandLog"}, - {0x081F0000, nullptr, "ClearSdmcLog"}, - {0x08200000, nullptr, "ClearNandLog"}, - {0x08210000, nullptr, "CardSlotIsInserted"}, - {0x08220000, nullptr, "CardSlotPowerOn"}, - {0x08230000, nullptr, "CardSlotPowerOff"}, - {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, - {0x08250040, nullptr, "CardNorDirectCommand"}, - {0x08260080, nullptr, "CardNorDirectCommandWithAddress"}, - {0x08270082, nullptr, "CardNorDirectRead"}, - {0x082800C2, nullptr, "CardNorDirectReadWithAddress"}, - {0x08290082, nullptr, "CardNorDirectWrite"}, - {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"}, - {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"}, - {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, - {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, - {0x082E0040, nullptr, "GetProductInfo"}, - {0x082F0040, nullptr, "GetProgramLaunchInfo"}, - {0x08300182, nullptr, "CreateExtSaveData"}, - {0x08310180, nullptr, "CreateSharedExtSaveData"}, - {0x08320102, nullptr, "ReadExtSaveDataIcon"}, - {0x08330082, nullptr, "EnumerateExtSaveData"}, - {0x08340082, nullptr, "EnumerateSharedExtSaveData"}, - {0x08350080, nullptr, "DeleteExtSaveData"}, - {0x08360080, nullptr, "DeleteSharedExtSaveData"}, - {0x08370040, nullptr, "SetCardSpiBaudRate"}, - {0x08380040, nullptr, "SetCardSpiBusMode"}, - {0x08390000, nullptr, "SendInitializeInfoTo9"}, - {0x083A0100, nullptr, "GetSpecialContentIndex"}, - {0x083B00C2, nullptr, "GetLegacyRomHeader"}, - {0x083C00C2, nullptr, "GetLegacyBannerData"}, - {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"}, - {0x083E00C2, nullptr, "QueryTotalQuotaSize"}, - {0x083F00C0, nullptr, "GetExtDataBlockSize"}, - {0x08400040, nullptr, "AbnegateAccessRight"}, - {0x08410000, nullptr, "DeleteSdmcRoot"}, - {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, - {0x08430000, nullptr, "InitializeCtrFileSystem"}, - {0x08440000, nullptr, "CreateSeed"}, - {0x084500C2, nullptr, "GetFormatInfo"}, - {0x08460102, nullptr, "GetLegacyRomHeader2"}, - {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, - {0x08480042, nullptr, "GetSdmcCtrRootPath"}, - {0x08490040, nullptr, "GetArchiveResource"}, - {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, - {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, - {0x084C0242, nullptr, "FormatSaveData"}, - {0x084D0102, nullptr, "GetLegacySubBannerData"}, - {0x084E0342, nullptr, "UpdateSha256Context"}, - {0x084F0102, nullptr, "ReadSpecialFile"}, - {0x08500040, nullptr, "GetSpecialFileSize"}, - {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, - {0x08610042, nullptr, "InitializeWithSdkVersion"}, - {0x08620040, nullptr, "SetPriority"}, - {0x08630000, nullptr, "GetPriority"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); -} - -Interface::~Interface() { -} - -} // namespace diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp new file mode 100644 index 000000000..9dc83291d --- /dev/null +++ b/src/core/hle/service/fs_user.cpp @@ -0,0 +1,352 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common.h" + +#include "fs_user.h" +#include "common/string_util.h" +#include "core/settings.h" +#include "core/hle/kernel/archive.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace FS_User + +namespace FS_User { + +// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it +// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make +// sure we don't mislead the application into thinking something worked. + +void Initialize(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per + // http://3dbrew.org/wiki/FS:Initialize#Request + cmd_buff[1] = 0; + + DEBUG_LOG(KERNEL, "called"); +} + +void OpenFile(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast<Handle>(cmd_buff[3]); + auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); + u32 filename_size = cmd_buff[5]; + FileSys::Mode mode; mode.hex = cmd_buff[6]; + u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. + u32 filename_ptr = cmd_buff[9]; + + FileSys::Path file_path(filename_type, filename_size, filename_ptr); + std::string file_string; + switch (file_path.GetType()) { + case FileSys::Char: + case FileSys::Wchar: + file_string = file_path.AsString(); + break; + default: + WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead"); + return; + } + + DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", + filename_type, filename_size, mode, attributes, file_string.c_str()); + + Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); + if (handle) { + cmd_buff[1] = 0; + cmd_buff[3] = handle; + } else { + ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); + // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. + cmd_buff[1] = -1; + } + + DEBUG_LOG(KERNEL, "called"); +} + +void OpenFileDirectly(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); + auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); + u32 archivename_size = cmd_buff[4]; + auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]); + u32 filename_size = cmd_buff[6]; + FileSys::Mode mode; mode.hex = cmd_buff[7]; + u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. + u32 archivename_ptr = cmd_buff[10]; + u32 filename_ptr = cmd_buff[12]; + + DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d file_type=%d file_size=%d file_mode=%d file_attrs=%d", + archivename_type, archivename_size, filename_type, filename_size, mode, attributes); + + if (archivename_type != FileSys::Empty) { + ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); + cmd_buff[1] = -1; + return; + } + + // TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it. + Handle archive_handle = Kernel::OpenArchive(archive_id); + if (archive_handle) { + cmd_buff[1] = 0; + // cmd_buff[2] isn't used according to 3dmoo's implementation. + cmd_buff[3] = archive_handle; + } else { + ERROR_LOG(KERNEL, "failed to get a handle for archive"); + // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. + cmd_buff[1] = -1; + return; + } + + FileSys::Path file_path(filename_type, filename_size, filename_ptr); + std::string file_string; + switch (file_path.GetType()) { + case FileSys::Char: + case FileSys::Wchar: + file_string = file_path.AsString(); + break; + default: + WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead"); + return; + } + + Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); + if (handle) { + cmd_buff[1] = 0; + cmd_buff[3] = handle; + } else { + ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); + // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. + cmd_buff[1] = -1; + } + + DEBUG_LOG(KERNEL, "called"); +} + +/* + * FS_User::CreateDirectory service function + * Inputs: + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : Directory path string type + * 5 : Directory path string size + * 8 : Directory path string data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void CreateDirectory(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast<Handle>(cmd_buff[3]); + auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]); + u32 dirname_size = cmd_buff[5]; + u32 dirname_ptr = cmd_buff[8]; + + FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); + std::string dir_string; + switch (dir_path.GetType()) { + case FileSys::Char: + case FileSys::Wchar: + dir_string = dir_path.AsString(); + break; + default: + cmd_buff[1] = -1; + return; + } + + DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); + + cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_string); + + DEBUG_LOG(KERNEL, "called"); +} + +void OpenDirectory(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast<Handle>(cmd_buff[2]); + auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]); + u32 dirname_size = cmd_buff[4]; + u32 dirname_ptr = cmd_buff[6]; + + FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); + std::string dir_string; + switch (dir_path.GetType()) { + case FileSys::Char: + case FileSys::Wchar: + dir_string = dir_path.AsString(); + break; + default: + cmd_buff[1] = -1; + return; + } + + DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); + + Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_string); + if (handle) { + cmd_buff[1] = 0; + cmd_buff[3] = handle; + } else { + ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str()); + // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. + cmd_buff[1] = -1; + } + + DEBUG_LOG(KERNEL, "called"); +} + +void OpenArchive(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); + auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); + u32 archivename_size = cmd_buff[3]; + u32 archivename_ptr = cmd_buff[5]; + + DEBUG_LOG(KERNEL, "type=%d size=%d", archivename_type, archivename_size); + + if (archivename_type != FileSys::Empty) { + ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); + cmd_buff[1] = -1; + return; + } + + Handle handle = Kernel::OpenArchive(archive_id); + if (handle) { + cmd_buff[1] = 0; + // cmd_buff[2] isn't used according to 3dmoo's implementation. + cmd_buff[3] = handle; + } else { + ERROR_LOG(KERNEL, "failed to get a handle for archive"); + // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily. + cmd_buff[1] = -1; + } + + DEBUG_LOG(KERNEL, "called"); +} + +/* +* FS_User::IsSdmcDetected service function +* Outputs: +* 1 : Result of function, 0 on success, otherwise error code +* 2 : Whether the Sdmc could be detected +*/ +void IsSdmcDetected(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + cmd_buff[1] = 0; + cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0; + + DEBUG_LOG(KERNEL, "called"); +} + +const Interface::FunctionInfo FunctionTable[] = { + {0x000100C6, nullptr, "Dummy1"}, + {0x040100C4, nullptr, "Control"}, + {0x08010002, Initialize, "Initialize"}, + {0x080201C2, OpenFile, "OpenFile"}, + {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, + {0x08040142, nullptr, "DeleteFile"}, + {0x08050244, nullptr, "RenameFile"}, + {0x08060142, nullptr, "DeleteDirectory"}, + {0x08070142, nullptr, "DeleteDirectoryRecursively"}, + {0x08080202, nullptr, "CreateFile"}, + {0x08090182, CreateDirectory, "CreateDirectory"}, + {0x080A0244, nullptr, "RenameDirectory"}, + {0x080B0102, OpenDirectory, "OpenDirectory"}, + {0x080C00C2, OpenArchive, "OpenArchive"}, + {0x080D0144, nullptr, "ControlArchive"}, + {0x080E0080, nullptr, "CloseArchive"}, + {0x080F0180, nullptr, "FormatThisUserSaveData"}, + {0x08100200, nullptr, "CreateSystemSaveData"}, + {0x08110040, nullptr, "DeleteSystemSaveData"}, + {0x08120080, nullptr, "GetFreeBytes"}, + {0x08130000, nullptr, "GetCardType"}, + {0x08140000, nullptr, "GetSdmcArchiveResource"}, + {0x08150000, nullptr, "GetNandArchiveResource"}, + {0x08160000, nullptr, "GetSdmcFatfsErro"}, + {0x08170000, IsSdmcDetected, "IsSdmcDetected"}, + {0x08180000, nullptr, "IsSdmcWritable"}, + {0x08190042, nullptr, "GetSdmcCid"}, + {0x081A0042, nullptr, "GetNandCid"}, + {0x081B0000, nullptr, "GetSdmcSpeedInfo"}, + {0x081C0000, nullptr, "GetNandSpeedInfo"}, + {0x081D0042, nullptr, "GetSdmcLog"}, + {0x081E0042, nullptr, "GetNandLog"}, + {0x081F0000, nullptr, "ClearSdmcLog"}, + {0x08200000, nullptr, "ClearNandLog"}, + {0x08210000, nullptr, "CardSlotIsInserted"}, + {0x08220000, nullptr, "CardSlotPowerOn"}, + {0x08230000, nullptr, "CardSlotPowerOff"}, + {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, + {0x08250040, nullptr, "CardNorDirectCommand"}, + {0x08260080, nullptr, "CardNorDirectCommandWithAddress"}, + {0x08270082, nullptr, "CardNorDirectRead"}, + {0x082800C2, nullptr, "CardNorDirectReadWithAddress"}, + {0x08290082, nullptr, "CardNorDirectWrite"}, + {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"}, + {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"}, + {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, + {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, + {0x082E0040, nullptr, "GetProductInfo"}, + {0x082F0040, nullptr, "GetProgramLaunchInfo"}, + {0x08300182, nullptr, "CreateExtSaveData"}, + {0x08310180, nullptr, "CreateSharedExtSaveData"}, + {0x08320102, nullptr, "ReadExtSaveDataIcon"}, + {0x08330082, nullptr, "EnumerateExtSaveData"}, + {0x08340082, nullptr, "EnumerateSharedExtSaveData"}, + {0x08350080, nullptr, "DeleteExtSaveData"}, + {0x08360080, nullptr, "DeleteSharedExtSaveData"}, + {0x08370040, nullptr, "SetCardSpiBaudRate"}, + {0x08380040, nullptr, "SetCardSpiBusMode"}, + {0x08390000, nullptr, "SendInitializeInfoTo9"}, + {0x083A0100, nullptr, "GetSpecialContentIndex"}, + {0x083B00C2, nullptr, "GetLegacyRomHeader"}, + {0x083C00C2, nullptr, "GetLegacyBannerData"}, + {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"}, + {0x083E00C2, nullptr, "QueryTotalQuotaSize"}, + {0x083F00C0, nullptr, "GetExtDataBlockSize"}, + {0x08400040, nullptr, "AbnegateAccessRight"}, + {0x08410000, nullptr, "DeleteSdmcRoot"}, + {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, + {0x08430000, nullptr, "InitializeCtrFileSystem"}, + {0x08440000, nullptr, "CreateSeed"}, + {0x084500C2, nullptr, "GetFormatInfo"}, + {0x08460102, nullptr, "GetLegacyRomHeader2"}, + {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, + {0x08480042, nullptr, "GetSdmcCtrRootPath"}, + {0x08490040, nullptr, "GetArchiveResource"}, + {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, + {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, + {0x084C0242, nullptr, "FormatSaveData"}, + {0x084D0102, nullptr, "GetLegacySubBannerData"}, + {0x084E0342, nullptr, "UpdateSha256Context"}, + {0x084F0102, nullptr, "ReadSpecialFile"}, + {0x08500040, nullptr, "GetSpecialFileSize"}, + {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, + {0x08610042, nullptr, "InitializeWithSdkVersion"}, + {0x08620040, nullptr, "SetPriority"}, + {0x08630000, nullptr, "GetPriority"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/fs.h b/src/core/hle/service/fs_user.h index 36f3697d3..005382540 100644 --- a/src/core/hle/service/fs.h +++ b/src/core/hle/service/fs_user.h @@ -23,7 +23,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "fs:USER"; } }; diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp_gpu.cpp index 46c5a8ddd..6119e6300 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -7,10 +7,9 @@ #include "common/bit_field.h" #include "core/mem_map.h" -#include "core/hle/hle.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" -#include "core/hle/service/gsp.h" +#include "gsp_gpu.h" #include "core/hw/gpu.h" #include "video_core/gpu_debugger.h" @@ -359,6 +358,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x001C0040, nullptr, "SetLedForceOff"}, {0x001D0040, nullptr, "SetTestCommand"}, {0x001E0080, nullptr, "SetInternalPriorities"}, + {0x001F0082, nullptr, "StoreDataCache"}, }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/gsp.h b/src/core/hle/service/gsp_gpu.h index a09d59dbb..177ce8da6 100644 --- a/src/core/hle/service/gsp.h +++ b/src/core/hle/service/gsp_gpu.h @@ -167,7 +167,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "gsp::Gpu"; } diff --git a/src/core/hle/service/hid.cpp b/src/core/hle/service/hid.cpp deleted file mode 100644 index 4e470795f..000000000 --- a/src/core/hle/service/hid.cpp +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common/log.h" - -#include "core/hle/hle.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/shared_memory.h" -#include "core/hle/service/hid.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace HID_User - -namespace HID_User { - -Handle g_shared_mem = 0; ///< Handle to shared memory region designated to HID_User service - -/** - * HID_User::GetIPCHandles service function - * Inputs: - * None - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unused - * 3 : Handle to HID_User shared memory - * 4 : Event signaled by HID_User - * 5 : Event signaled by HID_User - * 6 : Event signaled by HID_User - * 7 : Gyroscope event - * 8 : Event signaled by HID_User - */ -void GetIPCHandles(Service::Interface* self) { - u32* cmd_buff = Service::GetCommandBuffer(); - - cmd_buff[1] = 0; // No error - cmd_buff[3] = g_shared_mem; - cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventA"); - cmd_buff[5] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventB"); - cmd_buff[6] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventC"); - cmd_buff[7] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope"); - cmd_buff[8] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventD"); - - DEBUG_LOG(KERNEL, "called"); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x000A0000, GetIPCHandles, "GetIPCHandles"}, - {0x000B0000, nullptr, "StartAnalogStickCalibration"}, - {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, - {0x00110000, nullptr, "EnableAccelerometer"}, - {0x00120000, nullptr, "DisableAccelerometer"}, - {0x00130000, nullptr, "EnableGyroscopeLow"}, - {0x00140000, nullptr, "DisableGyroscopeLow"}, - {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, - {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, - {0x00170000, nullptr, "GetSoundVolume"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - g_shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object - - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); -} - -Interface::~Interface() { -} - -} // namespace diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp new file mode 100644 index 000000000..0eb32ba4a --- /dev/null +++ b/src/core/hle/service/hid_user.cpp @@ -0,0 +1,205 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" + +#include "core/hle/hle.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "hid_user.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace HID_User + +namespace HID_User { + +// Handle to shared memory region designated to HID_User service +static Handle shared_mem = 0; + +// Event handles +static Handle event_pad_or_touch_1 = 0; +static Handle event_pad_or_touch_2 = 0; +static Handle event_accelerometer = 0; +static Handle event_gyroscope = 0; +static Handle event_debug_pad = 0; + +// Next Pad state update information +static PadState next_state = {{0}}; +static u32 next_index = 0; +static s16 next_circle_x = 0; +static s16 next_circle_y = 0; + +/** + * Gets a pointer to the PadData structure inside HID shared memory + */ +static inline PadData* GetPadData() { + if (0 == shared_mem) + return nullptr; + + return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0)); +} + +/** + * Circle Pad from keys. + * + * This is implemented as "pushed all the way to an edge (max) or centered (0)". + * + * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions. + */ +void UpdateNextCirclePadState() { + static const s16 max_value = 0x9C; + next_circle_x = next_state.circle_left ? -max_value : 0x0; + next_circle_x += next_state.circle_right ? max_value : 0x0; + next_circle_y = next_state.circle_down ? -max_value : 0x0; + next_circle_y += next_state.circle_up ? max_value : 0x0; +} + +/** + * Sets a Pad state (button or button combo) as pressed + */ +void PadButtonPress(PadState pad_state) { + next_state.hex |= pad_state.hex; + UpdateNextCirclePadState(); +} + +/** + * Sets a Pad state (button or button combo) as released + */ +void PadButtonRelease(PadState pad_state) { + next_state.hex &= ~pad_state.hex; + UpdateNextCirclePadState(); +} + +/** + * Called after all Pad changes to be included in this update have been made, + * including both Pad key changes and analog circle Pad changes. + */ +void PadUpdateComplete() { + PadData* pad_data = GetPadData(); + + if (pad_data == nullptr) { + return; + } + + // Update PadData struct + pad_data->current_state.hex = next_state.hex; + pad_data->index = next_index; + next_index = (next_index + 1) % pad_data->entries.size(); + + // Get the previous Pad state + u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size(); + PadState old_state = pad_data->entries[last_entry_index].current_state; + + // Compute bitmask with 1s for bits different from the old state + PadState changed; + changed.hex = (next_state.hex ^ old_state.hex); + + // Compute what was added + PadState additions; + additions.hex = changed.hex & next_state.hex; + + // Compute what was removed + PadState removals; + removals.hex = changed.hex & old_state.hex; + + // Get the current Pad entry + PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index]; + + // Update entry properties + current_pad_entry->current_state.hex = next_state.hex; + current_pad_entry->delta_additions.hex = additions.hex; + current_pad_entry->delta_removals.hex = removals.hex; + + // Set circle Pad + current_pad_entry->circle_pad_x = next_circle_x; + current_pad_entry->circle_pad_y = next_circle_y; + + // If we just updated index 0, provide a new timestamp + if (pad_data->index == 0) { + pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks; + pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks(); + } + + // Signal both handles when there's an update to Pad or touch + Kernel::SignalEvent(event_pad_or_touch_1); + Kernel::SignalEvent(event_pad_or_touch_2); +} + + +// TODO(peachum): +// Add a method for setting analog input from joystick device for the circle Pad. +// +// This method should: +// * Be called after both PadButton<Press, Release>(). +// * Be called before PadUpdateComplete() +// * Set current PadEntry.circle_pad_<axis> using analog data +// * Set PadData.raw_circle_pad_data +// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_x >= 41 +// * Set PadData.current_state.circle_up = 1 if current PadEntry.circle_pad_y >= 41 +// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 +// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 + + +/** + * HID_User::GetIPCHandles service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Unused + * 3 : Handle to HID_User shared memory + * 4 : Event signaled by HID_User + * 5 : Event signaled by HID_User + * 6 : Event signaled by HID_User + * 7 : Gyroscope event + * 8 : Event signaled by HID_User + */ +void GetIPCHandles(Service::Interface* self) { + u32* cmd_buff = Service::GetCommandBuffer(); + + cmd_buff[1] = 0; // No error + cmd_buff[3] = shared_mem; + cmd_buff[4] = event_pad_or_touch_1; + cmd_buff[5] = event_pad_or_touch_2; + cmd_buff[6] = event_accelerometer; + cmd_buff[7] = event_gyroscope; + cmd_buff[8] = event_debug_pad; + + DEBUG_LOG(KERNEL, "called"); +} + +const Interface::FunctionInfo FunctionTable[] = { + {0x000A0000, GetIPCHandles, "GetIPCHandles"}, + {0x000B0000, nullptr, "StartAnalogStickCalibration"}, + {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, + {0x00110000, nullptr, "EnableAccelerometer"}, + {0x00120000, nullptr, "DisableAccelerometer"}, + {0x00130000, nullptr, "EnableGyroscopeLow"}, + {0x00140000, nullptr, "DisableGyroscopeLow"}, + {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, + {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, + {0x00170000, nullptr, "GetSoundVolume"}, +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + shared_mem = Kernel::CreateSharedMemory("HID_User:SharedMem"); // Create shared memory object + + // Create event handles + event_pad_or_touch_1 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch1"); + event_pad_or_touch_2 = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventPadOrTouch2"); + event_accelerometer = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventAccelerometer"); + event_gyroscope = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventGyroscope"); + event_debug_pad = Kernel::CreateEvent(RESETTYPE_ONESHOT, "HID_User:EventDebugPad"); + + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/hid_user.h b/src/core/hle/service/hid_user.h new file mode 100644 index 000000000..9f6c4d5ed --- /dev/null +++ b/src/core/hle/service/hid_user.h @@ -0,0 +1,120 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" +#include "common/bit_field.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace HID_User + +// This service is used for interfacing to physical user controls. +// Uses include game pad controls, touchscreen, accelerometers, gyroscopes, and debug pad. + +namespace HID_User { + +/** + * Structure of a Pad controller state. + */ +struct PadState { + union { + u32 hex; + + BitField<0, 1, u32> a; + BitField<1, 1, u32> b; + BitField<2, 1, u32> select; + BitField<3, 1, u32> start; + BitField<4, 1, u32> right; + BitField<5, 1, u32> left; + BitField<6, 1, u32> up; + BitField<7, 1, u32> down; + BitField<8, 1, u32> r; + BitField<9, 1, u32> l; + BitField<10, 1, u32> x; + BitField<11, 1, u32> y; + + BitField<28, 1, u32> circle_right; + BitField<29, 1, u32> circle_left; + BitField<30, 1, u32> circle_up; + BitField<31, 1, u32> circle_down; + }; +}; + +/** + * Structure of a single entry in the PadData's Pad state history array. + */ +struct PadDataEntry { + PadState current_state; + PadState delta_additions; + PadState delta_removals; + + s16 circle_pad_x; + s16 circle_pad_y; +}; + +/** + * Structure of all data related to the 3DS Pad. + */ +struct PadData { + s64 index_reset_ticks; + s64 index_reset_ticks_previous; + u32 index; // the index of the last updated Pad state history element + + u32 pad1; + u32 pad2; + + PadState current_state; // same as entries[index].current_state + u32 raw_circle_pad_data; + + u32 pad3; + + std::array<PadDataEntry, 8> entries; // Pad state history +}; + +// Pre-defined PadStates for single button presses +const PadState PAD_NONE = {{0}}; +const PadState PAD_A = {{1u << 0}}; +const PadState PAD_B = {{1u << 1}}; +const PadState PAD_SELECT = {{1u << 2}}; +const PadState PAD_START = {{1u << 3}}; +const PadState PAD_RIGHT = {{1u << 4}}; +const PadState PAD_LEFT = {{1u << 5}}; +const PadState PAD_UP = {{1u << 6}}; +const PadState PAD_DOWN = {{1u << 7}}; +const PadState PAD_R = {{1u << 8}}; +const PadState PAD_L = {{1u << 9}}; +const PadState PAD_X = {{1u << 10}}; +const PadState PAD_Y = {{1u << 11}}; +const PadState PAD_CIRCLE_RIGHT = {{1u << 28}}; +const PadState PAD_CIRCLE_LEFT = {{1u << 29}}; +const PadState PAD_CIRCLE_UP = {{1u << 30}}; +const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; + +// Methods for updating the HID module's state +void PadButtonPress(PadState pad_state); +void PadButtonRelease(PadState pad_state); +void PadUpdateComplete(); + +/** + * HID service interface. + */ +class Interface : public Service::Interface { +public: + + Interface(); + + ~Interface(); + + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const override { + return "hid:USER"; + } + +}; + +} // namespace diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp new file mode 100644 index 000000000..58051f133 --- /dev/null +++ b/src/core/hle/service/mic_u.cpp @@ -0,0 +1,43 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/mic_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace MIC_U + +namespace MIC_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010042, nullptr, "MapSharedMem"}, + {0x00020000, nullptr, "UnmapSharedMem"}, + {0x00030140, nullptr, "Initialize"}, + {0x00040040, nullptr, "AdjustSampling"}, + {0x00050000, nullptr, "StopSampling"}, + {0x00060000, nullptr, "IsSampling"}, + {0x00070000, nullptr, "GetEventHandle"}, + {0x00080040, nullptr, "SetControl"}, + {0x00090000, nullptr, "GetControl"}, + {0x000A0040, nullptr, "SetBias"}, + {0x000B0000, nullptr, "GetBias"}, + {0x000C0042, nullptr, "size"}, + {0x000D0040, nullptr, "SetClamp"}, + {0x000E0000, nullptr, "GetClamp"}, + {0x000F0040, nullptr, "unknown_input1"}, + {0x00100040, nullptr, "unknown_input2"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h new file mode 100644 index 000000000..72ba048ef --- /dev/null +++ b/src/core/hle/service/mic_u.h @@ -0,0 +1,29 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace MIC_U + +// mic service + +namespace MIC_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "mic:u"; + } +}; + +} // namespace diff --git a/src/core/hle/service/ndm.cpp b/src/core/hle/service/ndm_u.cpp index 48755b6a7..37c0661bf 100644 --- a/src/core/hle/service/ndm.cpp +++ b/src/core/hle/service/ndm_u.cpp @@ -2,10 +2,8 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include "common/log.h" - #include "core/hle/hle.h" -#include "core/hle/service/ndm.h" +#include "ndm_u.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace NDM_U diff --git a/src/core/hle/service/ndm.h b/src/core/hle/service/ndm_u.h index d5ec28f5b..2ca9fcf22 100644 --- a/src/core/hle/service/ndm.h +++ b/src/core/hle/service/ndm_u.h @@ -24,7 +24,7 @@ public: * Gets the string port name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "ndm:u"; } diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp new file mode 100644 index 000000000..14df86d85 --- /dev/null +++ b/src/core/hle/service/nwm_uds.cpp @@ -0,0 +1,35 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/nwm_uds.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace NWM_UDS + +namespace NWM_UDS { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00030000, nullptr, "Shutdown"}, + {0x000F0404, nullptr, "RecvBeaconBroadcastData"}, + {0x00100042, nullptr, "SetBeaconAdditionalData"}, + {0x001400C0, nullptr, "RecvBroadcastDataFrame"}, + {0x001B0302, nullptr, "Initialize"}, + {0x001D0044, nullptr, "BeginHostingNetwork"}, + {0x001E0084, nullptr, "ConnectToNetwork"}, + {0x001F0006, nullptr, "DecryptBeaconData"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h new file mode 100644 index 000000000..a956ca812 --- /dev/null +++ b/src/core/hle/service/nwm_uds.h @@ -0,0 +1,29 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace NWM_UDS + +// local-WLAN service + +namespace NWM_UDS { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "nwm:UDS"; + } +}; + +} // namespace diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp new file mode 100644 index 000000000..f6a14d509 --- /dev/null +++ b/src/core/hle/service/ptm_u.cpp @@ -0,0 +1,42 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ptm_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace PTM_U + +namespace PTM_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010002, nullptr, "RegisterAlarmClient"}, + {0x00020080, nullptr, "SetRtcAlarm"}, + {0x00030000, nullptr, "GetRtcAlarm"}, + {0x00040000, nullptr, "CancelRtcAlarm"}, + {0x00050000, nullptr, "GetAdapterState"}, + {0x00060000, nullptr, "GetShellState "}, + {0x00070000, nullptr, "GetBatteryLevel"}, + {0x00080000, nullptr, "GetBatteryChargeState"}, + {0x00090000, nullptr, "GetPedometerState"}, + {0x000A0042, nullptr, "GetStepHistoryEntry"}, + {0x000B00C2, nullptr, "GetStepHistory "}, + {0x000C0000, nullptr, "GetTotalStepCount "}, + {0x000D0040, nullptr, "SetPedometerRecordingMode"}, + {0x000E0000, nullptr, "GetPedometerRecordingMode"}, + {0x000F0084, nullptr, "GetStepHistoryAll"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm_u.h new file mode 100644 index 000000000..82749fa39 --- /dev/null +++ b/src/core/hle/service/ptm_u.h @@ -0,0 +1,29 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace PTM_U + +// ptm service + +namespace PTM_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "ptm:u"; + } +}; + +} // namespace diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 00ac1c9c6..bb0f80e98 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -3,20 +3,25 @@ // Refer to the license.txt file included. #include "common/common.h" -#include "common/log.h" #include "common/string_util.h" -#include "core/hle/hle.h" - #include "core/hle/service/service.h" -#include "core/hle/service/apt.h" -#include "core/hle/service/fs.h" -#include "core/hle/service/gsp.h" -#include "core/hle/service/hid.h" -#include "core/hle/service/ndm.h" +#include "core/hle/service/ac_u.h" +#include "core/hle/service/apt_u.h" +#include "core/hle/service/cfg_u.h" +#include "core/hle/service/dsp_dsp.h" +#include "core/hle/service/err_f.h" +#include "core/hle/service/fs_user.h" +#include "core/hle/service/frd_u.h" +#include "core/hle/service/gsp_gpu.h" +#include "core/hle/service/hid_user.h" +#include "core/hle/service/mic_u.h" +#include "core/hle/service/ndm_u.h" +#include "core/hle/service/nwm_uds.h" +#include "core/hle/service/ptm_u.h" +#include "core/hle/service/soc_u.h" #include "core/hle/service/srv.h" - -#include "core/hle/kernel/kernel.h" +#include "core/hle/service/ssl_c.h" namespace Service { @@ -71,11 +76,21 @@ void Init() { g_manager = new Manager; g_manager->AddService(new SRV::Interface); + g_manager->AddService(new AC_U::Interface); g_manager->AddService(new APT_U::Interface); + g_manager->AddService(new CFG_U::Interface); + g_manager->AddService(new DSP_DSP::Interface); + g_manager->AddService(new ERR_F::Interface); + g_manager->AddService(new FRD_U::Interface); g_manager->AddService(new FS_User::Interface); g_manager->AddService(new GSP_GPU::Interface); g_manager->AddService(new HID_User::Interface); + g_manager->AddService(new MIC_U::Interface); g_manager->AddService(new NDM_U::Interface); + g_manager->AddService(new NWM_UDS::Interface); + g_manager->AddService(new PTM_U::Interface); + g_manager->AddService(new SOC_U::Interface); + g_manager->AddService(new SSL_C::Interface); NOTICE_LOG(HLE, "initialized OK"); } diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index c0e803bda..2f5a866c9 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -39,11 +39,11 @@ class Interface : public Kernel::Object { friend class Manager; public: - std::string GetName() const { return GetPortName(); } - std::string GetTypeName() const { return GetPortName(); } + std::string GetName() const override { return GetPortName(); } + std::string GetTypeName() const override { return GetPortName(); } static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; } - Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Service; } + Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Service; } typedef void (*Function)(Interface*); @@ -80,7 +80,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result SyncRequest(bool* wait) { + Result SyncRequest(bool* wait) override { u32* cmd_buff = GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); @@ -113,7 +113,7 @@ public: * @param wait Boolean wait set if current thread should wait as a result of sync operation * @return Result of operation, 0 on success, otherwise error code */ - Result WaitSynchronization(bool* wait) { + Result WaitSynchronization(bool* wait) override { // TODO(bunnei): ImplementMe ERROR_LOG(OSHLE, "unimplemented function"); return 0; diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp new file mode 100644 index 000000000..2f8910468 --- /dev/null +++ b/src/core/hle/service/soc_u.cpp @@ -0,0 +1,58 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/soc_u.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SOC_U + +namespace SOC_U { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010044, nullptr, "InitializeSockets"}, + {0x000200C2, nullptr, "socket"}, + {0x00030082, nullptr, "listen"}, + {0x00040082, nullptr, "accept"}, + {0x00050084, nullptr, "bind"}, + {0x00060084, nullptr, "connect"}, + {0x00070104, nullptr, "recvfrom_other"}, + {0x00080102, nullptr, "recvfrom"}, + {0x00090106, nullptr, "sendto_other"}, + {0x000A0106, nullptr, "sendto"}, + {0x000B0042, nullptr, "close"}, + {0x000C0082, nullptr, "shutdown"}, + {0x000D0082, nullptr, "gethostbyname"}, + {0x000E00C2, nullptr, "gethostbyaddr"}, + {0x000F0106, nullptr, "unknown_resolve_ip"}, + {0x00110102, nullptr, "getsockopt"}, + {0x00120104, nullptr, "setsockopt"}, + {0x001300C2, nullptr, "fcntl"}, + {0x00140084, nullptr, "poll"}, + {0x00150042, nullptr, "sockatmark"}, + {0x00160000, nullptr, "gethostid"}, + {0x00170082, nullptr, "getsockname"}, + {0x00180082, nullptr, "getpeername"}, + {0x00190000, nullptr, "ShutdownSockets"}, + {0x001A00C0, nullptr, "GetNetworkOpt"}, + {0x001B0040, nullptr, "ICMPSocket"}, + {0x001C0104, nullptr, "ICMPPing"}, + {0x001D0040, nullptr, "ICMPCancel"}, + {0x001E0040, nullptr, "ICMPClose"}, + {0x001F0040, nullptr, "GetResolverInfo"}, + {0x00210002, nullptr, "CloseSockets"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h new file mode 100644 index 000000000..e27a2b1fe --- /dev/null +++ b/src/core/hle/service/soc_u.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SOC_U + +namespace SOC_U { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "soc:U"; + } +}; + +} // namespace diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 23be3cf2c..6c02a43d9 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -4,7 +4,6 @@ #include "core/hle/hle.h" #include "core/hle/service/srv.h" -#include "core/hle/service/service.h" #include "core/hle/kernel/event.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -58,6 +57,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00030100, nullptr, "RegisterService"}, {0x000400C0, nullptr, "UnregisterService"}, {0x00050100, GetServiceHandle, "GetServiceHandle"}, + {0x000B0000, nullptr, "ReceiveNotification"}, + {0x000C0080, nullptr, "PublishToSubscriber"} }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h index 9451472de..6d5fe5048 100644 --- a/src/core/hle/service/srv.h +++ b/src/core/hle/service/srv.h @@ -22,7 +22,7 @@ public: * Gets the string name used by CTROS for the service * @return Port name of service */ - std::string GetPortName() const { + std::string GetPortName() const override { return "srv:"; } diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp new file mode 100644 index 000000000..4aa660ecc --- /dev/null +++ b/src/core/hle/service/ssl_c.cpp @@ -0,0 +1,31 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/log.h" +#include "core/hle/hle.h" +#include "core/hle/service/ssl_c.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SSL_C + +namespace SSL_C { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000200C2, nullptr, "CreateContext"}, + {0x00050082, nullptr, "AddTrustedRootCA"}, + {0x00150082, nullptr, "Read"}, + {0x00170082, nullptr, "Write"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h new file mode 100644 index 000000000..7b4e7fd8a --- /dev/null +++ b/src/core/hle/service/ssl_c.h @@ -0,0 +1,27 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace SSL_C + +namespace SSL_C { + +class Interface : public Service::Interface { +public: + Interface(); + ~Interface(); + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const { + return "ssl:C"; + } +}; + +} // namespace diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index bdcfae6f5..1eda36c53 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include <map> -#include <string> #include "common/string_util.h" #include "common/symbols.h" @@ -12,13 +11,11 @@ #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/event.h" -#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/mutex.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/thread.h" #include "core/hle/function_wrappers.h" -#include "core/hle/svc.h" #include "core/hle/service/service.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -118,7 +115,7 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) { Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); - DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%d", handle, object->GetTypeName().c_str(), + DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds); _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); @@ -141,7 +138,7 @@ Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wa bool unlock_all = true; bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated - DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%d", + DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", handle_count, (wait_all ? "true" : "false"), nano_seconds); // Iterate through each handle, synchronize kernel object @@ -221,7 +218,7 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p TSymbol symbol = Symbols::GetSymbol(entry_point); name = symbol.name; } else { - name = StringFromFormat("unknown-%08x", entry_point); + name = Common::StringFromFormat("unknown-%08x", entry_point); } Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id, @@ -327,7 +324,7 @@ Result ClearEvent(Handle evt) { /// Sleep the current thread void SleepThread(s64 nanoseconds) { - DEBUG_LOG(SVC, "called nanoseconds=%d", nanoseconds); + DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds); } /// This returns the total CPU ticks elapsed since the CPU was powered-on diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 8709b8eb7..3ad801c63 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -3,14 +3,13 @@ // Refer to the license.txt file included. #include "common/common_types.h" -#include "common/log.h" +#include "core/settings.h" #include "core/core.h" #include "core/mem_map.h" #include "core/hle/hle.h" -#include "core/hle/kernel/thread.h" -#include "core/hle/service/gsp.h" +#include "core/hle/service/gsp_gpu.h" #include "core/hw/gpu.h" @@ -26,14 +25,17 @@ u32 g_cur_line = 0; ///< Current vertical screen line u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame +static u32 kFrameCycles = 0; ///< 268MHz / 60 frames per second +static u32 kFrameTicks = 0; ///< Approximate number of instructions/frame + template <typename T> inline void Read(T &var, const u32 raw_addr) { u32 addr = raw_addr - 0x1EF00000; - int index = addr / 4; + u32 index = addr / 4; // Reads other than u32 are untested, so I'd rather have them abort than silently fail if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { - ERROR_LOG(GPU, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + ERROR_LOG(GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); return; } @@ -43,15 +45,15 @@ inline void Read(T &var, const u32 raw_addr) { template <typename T> inline void Write(u32 addr, const T data) { addr -= 0x1EF00000; - int index = addr / 4; + u32 index = addr / 4; // Writes other than u32 are untested, so I'd rather have them abort than silently fail if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { - ERROR_LOG(GPU, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); return; } - g_regs[index] = data; + g_regs[index] = static_cast<u32>(data); switch (index) { @@ -83,15 +85,15 @@ inline void Write(u32 addr, const T data) { u8* source_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); u8* dest_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); - for (int y = 0; y < config.output_height; ++y) { + for (u32 y = 0; y < config.output_height; ++y) { // TODO: Why does the register seem to hold twice the framebuffer width? - for (int x = 0; x < config.output_width; ++x) { + for (u32 x = 0; x < config.output_width; ++x) { struct { int r, g, b, a; } source_color = { 0, 0, 0, 0 }; switch (config.input_format) { - case Regs::FramebufferFormat::RGBA8: + case Regs::PixelFormat::RGBA8: { // TODO: Most likely got the component order messed up. u8* srcptr = source_pointer + x * 4 + y * config.input_width * 4; @@ -108,7 +110,7 @@ inline void Write(u32 addr, const T data) { } switch (config.output_format) { - /*case Regs::FramebufferFormat::RGBA8: + /*case Regs::PixelFormat::RGBA8: { // TODO: Untested u8* dstptr = (u32*)(dest_pointer + x * 4 + y * config.output_width * 4); @@ -119,7 +121,7 @@ inline void Write(u32 addr, const T data) { break; }*/ - case Regs::FramebufferFormat::RGB8: + case Regs::PixelFormat::RGB8: { // TODO: Most likely got the component order messed up. u8* dstptr = dest_pointer + x * 3 + y * config.output_width * 3; @@ -136,10 +138,10 @@ inline void Write(u32 addr, const T data) { } } - DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%dx%d)-> 0x%08x(%dx%d), dst format %x", + DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", config.output_height * config.output_width * 4, - config.GetPhysicalInputAddress(), (int)config.input_width, (int)config.input_height, - config.GetPhysicalOutputAddress(), (int)config.output_width, (int)config.output_height, + config.GetPhysicalInputAddress(), config.input_width, config.input_height, + config.GetPhysicalOutputAddress(), config.output_width, config.output_height, config.output_format.Value()); } break; @@ -216,6 +218,9 @@ void Update() { /// Initialize hardware void Init() { + kFrameCycles = 268123480 / Settings::values.gpu_refresh_rate; + kFrameTicks = kFrameCycles / 3; + g_cur_line = 0; g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks(); @@ -238,13 +243,13 @@ void Init() { framebuffer_top.width = 240; framebuffer_top.height = 400; framebuffer_top.stride = 3 * 240; - framebuffer_top.color_format = Regs::FramebufferFormat::RGB8; + framebuffer_top.color_format = Regs::PixelFormat::RGB8; framebuffer_top.active_fb = 0; framebuffer_sub.width = 240; framebuffer_sub.height = 320; framebuffer_sub.stride = 3 * 240; - framebuffer_sub.color_format = Regs::FramebufferFormat::RGB8; + framebuffer_sub.color_format = Regs::PixelFormat::RGB8; framebuffer_sub.active_fb = 0; NOTICE_LOG(GPU, "initialized OK"); diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 7186bfa84..3fa7b9ccf 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h @@ -11,9 +11,6 @@ namespace GPU { -static const u32 kFrameCycles = 268123480 / 60; ///< 268MHz / 60 frames per second -static const u32 kFrameTicks = kFrameCycles / 3; ///< Approximate number of instructions/frame - // Returns index corresponding to the Regs member labeled by field_name // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])). @@ -56,7 +53,7 @@ struct Regs { "Structure size and register block length don't match") #endif - enum class FramebufferFormat : u32 { + enum class PixelFormat : u32 { RGBA8 = 0, RGB8 = 1, RGB565 = 2, @@ -84,9 +81,7 @@ struct Regs { INSERT_PADDING_WORDS(0x10b); - struct { - using Format = Regs::FramebufferFormat; - + struct FramebufferConfig { union { u32 size; @@ -102,7 +97,7 @@ struct Regs { union { u32 format; - BitField< 0, 3, Format> color_format; + BitField< 0, 3, PixelFormat> color_format; }; INSERT_PADDING_WORDS(0x1); @@ -130,8 +125,6 @@ struct Regs { INSERT_PADDING_WORDS(0x169); struct { - using Format = Regs::FramebufferFormat; - u32 input_address; u32 output_address; @@ -161,8 +154,8 @@ struct Regs { u32 flags; BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true - BitField< 8, 3, Format> input_format; - BitField<12, 3, Format> output_format; + BitField< 8, 3, PixelFormat> input_format; + BitField<12, 3, PixelFormat> output_format; BitField<16, 1, u32> output_tiled; // stores output in a tiled format }; @@ -201,7 +194,7 @@ struct Regs { #undef INSERT_PADDING_WORDS_HELPER2 #undef INSERT_PADDING_WORDS - static inline int NumIds() { + static inline size_t NumIds() { return sizeof(Regs) / sizeof(u32); } diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index ed70486e6..33f75c50a 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include "common/common_types.h" -#include "common/log.h" #include "core/hw/hw.h" #include "core/hw/gpu.h" @@ -51,7 +50,7 @@ inline void Read(T &var, const u32 addr) { break; default: - ERROR_LOG(HW, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + ERROR_LOG(HW, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); } } @@ -69,7 +68,7 @@ inline void Write(u32 addr, const T data) { break; default: - ERROR_LOG(HW, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); } } diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp index f6aa72d16..e29a773f1 100644 --- a/src/core/hw/ndma.cpp +++ b/src/core/hw/ndma.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include "common/common_types.h" -#include "common/log.h" #include "core/hw/ndma.h" @@ -11,12 +10,12 @@ namespace NDMA { template <typename T> inline void Read(T &var, const u32 addr) { - ERROR_LOG(NDMA, "unknown Read%d @ 0x%08X", sizeof(var) * 8, addr); + ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); } template <typename T> inline void Write(u32 addr, const T data) { - ERROR_LOG(NDMA, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); + ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); } // Explicitly instantiate template functions because we aren't defining this in the header: diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 76c9d6d54..389d5a8c9 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -351,7 +351,7 @@ ResultStatus AppLoader_ELF::Load() { if (is_loaded) return ResultStatus::ErrorAlreadyLoaded; - File::IOFile file(filename, "rb"); + FileUtil::IOFile file(filename, "rb"); if (file.IsOpen()) { u32 size = (u32)file.GetSize(); diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 365f5a277..a268e021a 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -5,7 +5,6 @@ #include <memory> #include "core/file_sys/archive_romfs.h" -#include "core/loader/loader.h" #include "core/loader/elf.h" #include "core/loader/ncch.h" #include "core/hle/kernel/archive.h" @@ -26,22 +25,23 @@ FileType IdentifyFile(const std::string &filename) { ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); return FileType::Error; } - std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : ""; - if (!strcasecmp(extension.c_str(), ".elf")) { - return FileType::ELF; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".axf")) { - return FileType::ELF; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".cxi")) { - return FileType::CXI; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".cci")) { - return FileType::CCI; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".bin")) { - return FileType::BIN; // TODO(bunnei): Do some filetype checking :p + size_t extension_loc = filename.find_last_of('.'); + if (extension_loc == std::string::npos) + return FileType::Unknown; + std::string extension = Common::ToLower(filename.substr(extension_loc)); + + // TODO(bunnei): Do actual filetype checking instead of naively checking the extension + if (extension == ".elf") { + return FileType::ELF; + } else if (extension == ".axf") { + return FileType::ELF; + } else if (extension == ".cxi") { + return FileType::CXI; + } else if (extension == ".cci") { + return FileType::CCI; + } else if (extension == ".bin") { + return FileType::BIN; } return FileType::Unknown; } @@ -78,7 +78,7 @@ ResultStatus LoadFile(const std::string& filename) { { INFO_LOG(LOADER, "Loading BIN file %s...", filename.c_str()); - File::IOFile file(filename, "rb"); + FileUtil::IOFile file(filename, "rb"); if (file.IsOpen()) { file.ReadBytes(Memory::GetPointer(Memory::EXEFS_CODE_VADDR), (size_t)file.GetSize()); diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 9af59e419..1e5501e6d 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -138,7 +138,7 @@ ResultStatus AppLoader_NCCH::LoadExec() const { */ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { // Iterate through the ExeFs archive until we find the .code file... - File::IOFile file(filename, "rb"); + FileUtil::IOFile file(filename, "rb"); if (file.IsOpen()) { for (int i = 0; i < kMaxSections; i++) { // Load the specified section... @@ -199,7 +199,7 @@ ResultStatus AppLoader_NCCH::Load() { if (is_loaded) return ResultStatus::ErrorAlreadyLoaded; - File::IOFile file(filename, "rb"); + FileUtil::IOFile file(filename, "rb"); if (file.IsOpen()) { file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); @@ -290,7 +290,7 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const { * @return ResultStatus result of function */ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { - File::IOFile file(filename, "rb"); + FileUtil::IOFile file(filename, "rb"); if (file.IsOpen()) { // Check if the NCCH has a RomFS... if (ncch_header.romfs_offset != 0 && ncch_header.romfs_size != 0) { diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index 14fc01471..cf12f24d9 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp @@ -6,7 +6,6 @@ #include "common/mem_arena.h" #include "core/mem_map.h" -#include "core/core.h" //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 391b75fc2..90951812b 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp @@ -8,7 +8,6 @@ #include "core/mem_map.h" #include "core/hw/hw.h" -#include "hle/hle.h" #include "hle/config_mem.h" namespace Memory { @@ -288,7 +287,7 @@ void Write64(const VAddr addr, const u64 data) { } void WriteBlock(const VAddr addr, const u8* data, const size_t size) { - int offset = 0; + u32 offset = 0; while (offset < (size & ~3)) { Write32(addr + offset, *(u32*)&data[offset]); offset += 4; diff --git a/src/core/settings.cpp b/src/core/settings.cpp new file mode 100644 index 000000000..c486f6274 --- /dev/null +++ b/src/core/settings.cpp @@ -0,0 +1,11 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "settings.h" + +namespace Settings { + +Values values = {}; + +} diff --git a/src/core/settings.h b/src/core/settings.h new file mode 100644 index 000000000..6a6265e18 --- /dev/null +++ b/src/core/settings.h @@ -0,0 +1,37 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +namespace Settings { + +struct Values { + // Controls + int pad_a_key; + int pad_b_key; + int pad_x_key; + int pad_y_key; + int pad_l_key; + int pad_r_key; + int pad_start_key; + int pad_select_key; + int pad_home_key; + int pad_dup_key; + int pad_ddown_key; + int pad_dleft_key; + int pad_dright_key; + int pad_sup_key; + int pad_sdown_key; + int pad_sleft_key; + int pad_sright_key; + + // Core + int cpu_core; + int gpu_refresh_rate; + + // Data Storage + bool use_virtual_sd; +} extern values; + +} diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp index 592f2f476..96d3dabe2 100644 --- a/src/video_core/clipper.cpp +++ b/src/video_core/clipper.cpp @@ -86,8 +86,8 @@ static void InitScreenCoordinates(OutputVertex& vtx) viewport.halfsize_x = float24::FromRawFloat24(registers.viewport_size_x); viewport.halfsize_y = float24::FromRawFloat24(registers.viewport_size_y); - viewport.offset_x = float24::FromFloat32(registers.viewport_corner.x); - viewport.offset_y = float24::FromFloat32(registers.viewport_corner.y); + viewport.offset_x = float24::FromFloat32(static_cast<float>(registers.viewport_corner.x)); + viewport.offset_y = float24::FromFloat32(static_cast<float>(registers.viewport_corner.y)); viewport.zscale = float24::FromRawFloat24(registers.viewport_depth_range); viewport.offset_z = float24::FromRawFloat24(registers.viewport_depth_far_plane); @@ -150,7 +150,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { InitScreenCoordinates(*(output_list[0])); InitScreenCoordinates(*(output_list[1])); - for (int i = 0; i < output_list.size() - 2; i ++) { + for (size_t i = 0; i < output_list.size() - 2; i ++) { OutputVertex& vtx0 = *(output_list[0]); OutputVertex& vtx1 = *(output_list[i+1]); OutputVertex& vtx2 = *(output_list[i+2]); @@ -158,8 +158,8 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { InitScreenCoordinates(vtx2); DEBUG_LOG(GPU, - "Triangle %d/%d (%d buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), " - "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " + "Triangle %lu/%lu (%lu buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), " + "(%.3lu, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", i,output_list.size(), buffer_vertices.size(), vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),output_list.size(), diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 9567a9849..1ec727698 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -63,8 +63,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { for (int component = 0; component < loader_config.component_count; ++component) { u32 attribute_index = loader_config.GetComponent(component); vertex_attribute_sources[attribute_index] = load_address; - vertex_attribute_strides[attribute_index] = loader_config.byte_count; - vertex_attribute_formats[attribute_index] = (u32)attribute_config.GetFormat(attribute_index); + vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); + vertex_attribute_formats[attribute_index] = static_cast<u32>(attribute_config.GetFormat(attribute_index)); vertex_attribute_elements[attribute_index] = attribute_config.GetNumElements(attribute_index); vertex_attribute_element_size[attribute_index] = attribute_config.GetElementSizeInBytes(attribute_index); load_address += attribute_config.GetStride(attribute_index); @@ -83,9 +83,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { PrimitiveAssembler<VertexShader::OutputVertex> clipper_primitive_assembler(registers.triangle_topology.Value()); PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(registers.triangle_topology.Value()); - for (int index = 0; index < registers.num_vertices; ++index) + for (unsigned int index = 0; index < registers.num_vertices; ++index) { - int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index; + unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index; if (is_indexed) { // TODO: Implement some sort of vertex cache! @@ -95,14 +95,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { VertexShader::InputVertex input; for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { - for (int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { + for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { const u8* srcdata = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]; const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata : (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata : (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata : *(float*)srcdata; input.attr[i][comp] = float24::FromFloat32(srcval); - DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08x + 0x%04x: %f", + DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f", comp, i, vertex, index, attribute_config.GetBaseAddress(), vertex_attribute_sources[i] - base_address, @@ -244,7 +244,7 @@ static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) { WritePicaReg(header.cmd_id, *read_pointer, write_mask); read_pointer += 2; - for (int i = 1; i < 1+header.extra_data_length; ++i) { + for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) { u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0); WritePicaReg(cmd, *read_pointer, write_mask); ++read_pointer; diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 48e6dd182..22b8e9950 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -203,7 +203,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data } else { it->component_mask = it->component_mask | component_mask; } - } catch (const std::out_of_range& oor) { + } catch (const std::out_of_range& ) { _dbg_assert_msg_(GPU, 0, "Unknown output attribute mapping"); ERROR_LOG(GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x", (int)output_attributes[i].map_x.Value(), @@ -235,7 +235,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data dvlp.swizzle_patterns_offset = write_offset - dvlp_offset; dvlp.swizzle_patterns_num_entries = swizzle_size; u32 dummy = 0; - for (int i = 0; i < swizzle_size; ++i) { + for (unsigned int i = 0; i < swizzle_size; ++i) { QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i])); QueueForWriting((u8*)&dummy, sizeof(dummy)); } @@ -278,7 +278,7 @@ void StartPicaTracing() bool IsPicaTracing() { - return is_pica_tracing; + return is_pica_tracing != 0; } void OnPicaRegWrite(u32 id, u32 value) @@ -336,7 +336,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { png_infop info_ptr = nullptr; // Open file for writing (binary mode) - File::IOFile fp(filename, "wb"); + FileUtil::IOFile fp(filename, "wb"); // Initialize write structure png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); @@ -428,7 +428,7 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages) using Operation = Pica::Regs::TevStageConfig::Operation; std::string stage_info = "Tev setup:\n"; - for (int index = 0; index < stages.size(); ++index) { + for (size_t index = 0; index < stages.size(); ++index) { const auto& tev_stage = stages[index]; const std::map<Source, std::string> source_map = { diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 5a81fcfcb..1242eb58f 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h @@ -10,7 +10,7 @@ #include "common/log.h" -#include "core/hle/service/gsp.h" +#include "core/hle/service/gsp_gpu.h" #include "command_processor.h" #include "pica.h" diff --git a/src/video_core/pica.h b/src/video_core/pica.h index cfdc9b934..5fe15a218 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -516,12 +516,12 @@ struct Regs { // Used for debugging purposes, so performance is not an issue here static std::string GetCommandName(int index) { std::map<u32, std::string> map; - Regs regs; // TODO: MSVC does not support using offsetof() on non-static data members even though this // is technically allowed since C++11. Hence, this functionality is disabled until // MSVC properly supports it. #ifndef _MSC_VER + Regs regs; #define ADD_FIELD(name) \ do { \ map.insert({PICA_REG_INDEX(name), #name}); \ @@ -563,7 +563,7 @@ struct Regs { return map[index]; } - static inline int NumIds() { + static inline size_t NumIds() { return sizeof(Regs) / sizeof(u32); } diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index b55391e5e..a35f0c0d8 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -65,7 +65,7 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, // vertex positions in rasterizer coordinates auto FloatToFix = [](float24 flt) { - return Fix12P4(flt.ToFloat32() * 16.0f); + return Fix12P4(static_cast<unsigned short>(flt.ToFloat32() * 16.0f)); }; auto ScreenToRasterizerCoordinates = [FloatToFix](const Math::Vec3<float24> vec) { return Math::Vec3<Fix12P4>{FloatToFix(vec.x), FloatToFix(vec.y), FloatToFix(vec.z)}; @@ -151,9 +151,9 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, auto w_inverse = Math::MakeVec(float24::FromFloat32(1.f) / v0.pos.w, float24::FromFloat32(1.f) / v1.pos.w, float24::FromFloat32(1.f) / v2.pos.w); - auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(w0), - float24::FromFloat32(w1), - float24::FromFloat32(w2)); + auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)), + float24::FromFloat32(static_cast<float>(w1)), + float24::FromFloat32(static_cast<float>(w2))); float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates); float24 interpolated_w_inverse = Math::Dot(w_inverse, baricentric_coordinates); @@ -195,8 +195,8 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0, // TODO(neobrain): Not sure if this swizzling pattern is used for all textures. // To be flexible in case different but similar patterns are used, we keep this // somewhat inefficient code around for now. - int s = (int)(u * float24::FromFloat32(registers.texture0.width)).ToFloat32(); - int t = (int)(v * float24::FromFloat32(registers.texture0.height)).ToFloat32(); + int s = (int)(u * float24::FromFloat32(static_cast<float>(registers.texture0.width))).ToFloat32(); + int t = (int)(v * float24::FromFloat32(static_cast<float>(registers.texture0.height))).ToFloat32(); int texel_index_within_tile = 0; for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { int sub_tile_width = 1 << block_size_index; diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 2650620b4..f1dbc9d17 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h @@ -19,7 +19,7 @@ public: RendererBase() : m_current_fps(0), m_current_frame(0) { } - ~RendererBase() { + virtual ~RendererBase() { } /// Swap buffers (render frame) diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 10239c8a7..a0eb0418c 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp @@ -29,10 +29,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result); glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); - std::vector<char> vertex_shader_error(info_log_length); - glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]); - if (info_log_length > 1) { + std::vector<char> vertex_shader_error(info_log_length); + glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]); DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]); } @@ -46,10 +45,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result); glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); - std::vector<char> fragment_shader_error(info_log_length); - glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]); - if (info_log_length > 1) { + std::vector<char> fragment_shader_error(info_log_length); + glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]); DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]); } @@ -65,10 +63,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { glGetProgramiv(program_id, GL_LINK_STATUS, &result); glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length); - std::vector<char> program_error(std::max(info_log_length, int(1))); - glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]); - if (info_log_length > 1) { + std::vector<char> program_error(info_log_length); + glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]); DEBUG_LOG(GPU, "%s", &program_error[0]); } diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h index 380648f45..0f88ab802 100644 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ b/src/video_core/renderer_opengl/gl_shaders.h @@ -6,34 +6,40 @@ namespace GLShaders { -static const char g_vertex_shader[] = R"( +const char g_vertex_shader[] = R"( #version 150 core -in vec3 position; -in vec2 texCoord; -out vec2 UV; +in vec2 vert_position; +in vec2 vert_tex_coord; +out vec2 frag_tex_coord; -mat3 window_scale = mat3( - vec3(1.0, 0.0, 0.0), - vec3(0.0, 5.0/6.0, 0.0), // TODO(princesspeachum): replace hard-coded aspect with uniform - vec3(0.0, 0.0, 1.0) - ); +// This is a truncated 3x3 matrix for 2D transformations: +// The upper-left 2x2 submatrix performs scaling/rotation/mirroring. +// The third column performs translation. +// The third row could be used for projection, which we don't need in 2D. It hence is assumed to +// implicitly be [0, 0, 1] +uniform mat3x2 modelview_matrix; void main() { - gl_Position.xyz = window_scale * position; - gl_Position.w = 1.0; - - UV = texCoord; -})"; + // Multiply input position by the rotscale part of the matrix and then manually translate by + // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector + // to `vec3(vert_position.xy, 1.0)` + gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); + frag_tex_coord = vert_tex_coord; +} +)"; -static const char g_fragment_shader[] = R"( +const char g_fragment_shader[] = R"( #version 150 core -in vec2 UV; -out vec3 color; -uniform sampler2D sampler; + +in vec2 frag_tex_coord; +out vec4 color; + +uniform sampler2D color_texture; void main() { - color = texture(sampler, UV).rgb; -})"; + color = texture(color_texture, frag_tex_coord); +} +)"; } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 0e4e06517..8483f79be 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -3,64 +3,51 @@ // Refer to the license.txt file included. #include "core/hw/gpu.h" - +#include "core/mem_map.h" +#include "common/emu_window.h" #include "video_core/video_core.h" #include "video_core/renderer_opengl/renderer_opengl.h" #include "video_core/renderer_opengl/gl_shader_util.h" #include "video_core/renderer_opengl/gl_shaders.h" -#include "core/mem_map.h" - #include <algorithm> -static const GLfloat kViewportAspectRatio = - (static_cast<float>(VideoCore::kScreenTopHeight) + VideoCore::kScreenBottomHeight) / VideoCore::kScreenTopWidth; - -// Fullscreen quad dimensions -static const GLfloat kTopScreenWidthNormalized = 2; -static const GLfloat kTopScreenHeightNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenTopHeight) / VideoCore::kScreenTopWidth); -static const GLfloat kBottomScreenWidthNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth); -static const GLfloat kBottomScreenHeightNormalized = kBottomScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomHeight) / VideoCore::kScreenBottomWidth); - -static const GLfloat g_vbuffer_top[] = { - // x, y, z u, v - -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, - 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, - 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f, - 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f, - -1.0f, kTopScreenHeightNormalized, 0.0f, 0.0f, 0.0f, - -1.0f, 0.0f, 0.0f, 0.0f, 1.0f -}; +/** + * Vertex structure that the drawn screen rectangles are composed of. + */ +struct ScreenRectVertex { + ScreenRectVertex(GLfloat x, GLfloat y, GLfloat u, GLfloat v) { + position[0] = x; + position[1] = y; + tex_coord[0] = u; + tex_coord[1] = v; + } -static const GLfloat g_vbuffer_bottom[] = { - // x, y, z u, v - -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f, - (kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 1.0f, 1.0f, - (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f, - (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f, - -(kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 0.0f, 0.0f, - -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f + GLfloat position[2]; + GLfloat tex_coord[2]; }; +/** + * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left + * corner and (width, height) on the lower-bottom. + * + * The projection part of the matrix is trivial, hence these operations are represented + * by a 3x2 matrix. + */ +static std::array<GLfloat, 3*2> MakeOrthographicMatrix(const float width, const float height) { + std::array<GLfloat, 3*2> matrix; + + matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f; + matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f; + // Last matrix row is implicitly assumed to be [0, 0, 1]. + + return matrix; +} + /// RendererOpenGL constructor RendererOpenGL::RendererOpenGL() { - resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; - - // Initialize screen info - const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0]; - const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1]; - - screen_info.Top().width = VideoCore::kScreenTopWidth; - screen_info.Top().height = VideoCore::kScreenTopHeight; - screen_info.Top().stride = framebuffer_top.stride; - screen_info.Top().flipped_xfb_data = xfb_top_flipped; - - screen_info.Bottom().width = VideoCore::kScreenBottomWidth; - screen_info.Bottom().height = VideoCore::kScreenBottomHeight; - screen_info.Bottom().stride = framebuffer_sub.stride; - screen_info.Bottom().flipped_xfb_data = xfb_bottom_flipped; } /// RendererOpenGL destructor @@ -71,17 +58,24 @@ RendererOpenGL::~RendererOpenGL() { void RendererOpenGL::SwapBuffers() { render_window->MakeCurrent(); - // EFB->XFB copy - // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some - // register write. - // - // TODO(princesspeachum): (related to above^) this should only be called when there's new data, not every frame. - // Currently this uploads data that shouldn't have changed. - common::Rect framebuffer_size(0, 0, resolution_width, resolution_height); - RenderXFB(framebuffer_size, framebuffer_size); + for(int i : {0, 1}) { + const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; + + if (textures[i].width != framebuffer.width || textures[i].height != framebuffer.height) { + // Reallocate texture if the framebuffer size has changed. + // This is expected to not happen very often and hence should not be a + // performance problem. + glBindTexture(GL_TEXTURE_2D, textures[i].handle); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, framebuffer.width, framebuffer.height, 0, + GL_BGR, GL_UNSIGNED_BYTE, nullptr); + textures[i].width = framebuffer.width; + textures[i].height = framebuffer.height; + } + + LoadFBToActiveGLTexture(GPU::g_regs.framebuffer_config[i], textures[i]); + } - // XFB->Window copy - RenderFramebuffer(); + DrawScreens(); // Swap buffers render_window->PollEvents(); @@ -89,144 +83,135 @@ void RendererOpenGL::SwapBuffers() { } /** - * Helper function to flip framebuffer from left-to-right to top-to-bottom - * @param raw_data Pointer to input raw framebuffer in V/RAM - * @param screen_info ScreenInfo structure with screen size and output buffer pointer - * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei + * Loads framebuffer from emulated memory into the active OpenGL texture. */ -void RendererOpenGL::FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info) { - for (int x = 0; x < screen_info.width; x++) { - int in_coord = x * screen_info.stride; - for (int y = screen_info.height-1; y >= 0; y--) { - // TODO: Properly support other framebuffer formats - int out_coord = (x + y * screen_info.width) * 3; - screen_info.flipped_xfb_data[out_coord] = raw_data[in_coord + 2]; // Red - screen_info.flipped_xfb_data[out_coord + 1] = raw_data[in_coord + 1]; // Green - screen_info.flipped_xfb_data[out_coord + 2] = raw_data[in_coord]; // Blue - in_coord += 3; - } - } +void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, + const TextureInfo& texture) { + const VAddr framebuffer_vaddr = Memory::PhysicalToVirtualAddress( + framebuffer.active_fb == 1 ? framebuffer.address_left2 : framebuffer.address_left1); + + DEBUG_LOG(GPU, "0x%08x bytes from 0x%08x(%dx%d), fmt %x", + framebuffer.stride * framebuffer.height, + framebuffer_vaddr, (int)framebuffer.width, + (int)framebuffer.height, (int)framebuffer.format); + + const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr); + + // TODO: Handle other pixel formats + _dbg_assert_msg_(RENDER, framebuffer.color_format == GPU::Regs::PixelFormat::RGB8, + "Unsupported 3DS pixel format."); + + size_t pixel_stride = framebuffer.stride / 3; + // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately + _dbg_assert_(RENDER, pixel_stride * 3 == framebuffer.stride); + // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default + // only allows rows to have a memory alignement of 4. + _dbg_assert_(RENDER, pixel_stride % 4 == 0); + + glBindTexture(GL_TEXTURE_2D, texture.handle); + glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); + + // Update existing texture + // TODO: Test what happens on hardware when you change the framebuffer dimensions so that they + // differ from the LCD resolution. + // TODO: Applications could theoretically crash Citra here by specifying too large + // framebuffer sizes. We should make sure that this cannot happen. + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height, + GL_BGR, GL_UNSIGNED_BYTE, framebuffer_data); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + glBindTexture(GL_TEXTURE_2D, 0); } /** - * Renders external framebuffer (XFB) - * @param src_rect Source rectangle in XFB to copy - * @param dst_rect Destination rectangle in output framebuffer to copy to + * Initializes the OpenGL state and creates persistent objects. */ -void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { - const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0]; - const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1]; - const u32 active_fb_top = (framebuffer_top.active_fb == 1) - ? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2) - : Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1); - const u32 active_fb_sub = (framebuffer_sub.active_fb == 1) - ? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2) - : Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1); - - DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x", - framebuffer_top.stride * framebuffer_top.height, - active_fb_top, (int)framebuffer_top.width, - (int)framebuffer_top.height, (int)framebuffer_top.format); - - FlipFramebuffer(Memory::GetPointer(active_fb_top), screen_info.Top()); - FlipFramebuffer(Memory::GetPointer(active_fb_sub), screen_info.Bottom()); - - for (int i = 0; i < 2; i++) { - ScreenInfo* current_screen = &screen_info[i]; - - glBindTexture(GL_TEXTURE_2D, current_screen->texture_id); - - // TODO: This should consider the GPU registers for framebuffer width, height and stride. - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, current_screen->width, current_screen->height, - GL_RGB, GL_UNSIGNED_BYTE, current_screen->flipped_xfb_data); - } - - glBindTexture(GL_TEXTURE_2D, 0); - - // TODO(princesspeachum): - // Only the subset src_rect of the GPU buffer - // should be copied into the texture of the relevant screen. - // - // The method's parameters also only include src_rect and dest_rec for one screen, - // so this may need to be changed (pair for each screen). -} +void RendererOpenGL::InitOpenGLObjects() { + glClearColor(1.0f, 1.0f, 1.0f, 0.0f); + glDisable(GL_DEPTH_TEST); -/// Initialize the FBO -void RendererOpenGL::InitFramebuffer() { + // Link shaders and get variable locations program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); - sampler_id = glGetUniformLocation(program_id, "sampler"); - attrib_position = glGetAttribLocation(program_id, "position"); - attrib_texcoord = glGetAttribLocation(program_id, "texCoord"); - - // Generate vertex buffers for both screens - glGenBuffers(1, &screen_info.Top().vertex_buffer_id); - glGenBuffers(1, &screen_info.Bottom().vertex_buffer_id); - - // Attach vertex data for top screen - glBindBuffer(GL_ARRAY_BUFFER, screen_info.Top().vertex_buffer_id); - glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_top), g_vbuffer_top, GL_STATIC_DRAW); - - // Attach vertex data for bottom screen - glBindBuffer(GL_ARRAY_BUFFER, screen_info.Bottom().vertex_buffer_id); - glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_bottom), g_vbuffer_bottom, GL_STATIC_DRAW); + uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix"); + uniform_color_texture = glGetUniformLocation(program_id, "color_texture"); + attrib_position = glGetAttribLocation(program_id, "vert_position"); + attrib_tex_coord = glGetAttribLocation(program_id, "vert_tex_coord"); - // Create color buffers for both screens - glGenTextures(1, &screen_info.Top().texture_id); - glGenTextures(1, &screen_info.Bottom().texture_id); + // Generate VBO handle for drawing + glGenBuffers(1, &vertex_buffer_handle); - for (int i = 0; i < 2; i++) { + // Generate VAO + glGenVertexArrays(1, &vertex_array_handle); + glBindVertexArray(vertex_array_handle); + + // Attach vertex data to VAO + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle); + glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); + glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, position)); + glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex), (GLvoid*)offsetof(ScreenRectVertex, tex_coord)); + glEnableVertexAttribArray(attrib_position); + glEnableVertexAttribArray(attrib_tex_coord); - ScreenInfo* current_screen = &screen_info[i]; + // Allocate textures for each screen + for (auto& texture : textures) { + glGenTextures(1, &texture.handle); - // Allocate texture - glBindTexture(GL_TEXTURE_2D, current_screen->vertex_buffer_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, current_screen->width, current_screen->height, - 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + // Allocation of storage is deferred until the first frame, when we + // know the framebuffer size. + glBindTexture(GL_TEXTURE_2D, texture.handle); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } - glBindTexture(GL_TEXTURE_2D, 0); } -void RendererOpenGL::RenderFramebuffer() { +/** + * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD rotation. + */ +void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h) { + std::array<ScreenRectVertex, 4> vertices = { + ScreenRectVertex(x, y, 1.f, 0.f), + ScreenRectVertex(x+w, y, 1.f, 1.f), + ScreenRectVertex(x, y+h, 0.f, 0.f), + ScreenRectVertex(x+w, y+h, 0.f, 1.f), + }; + + glBindTexture(GL_TEXTURE_2D, texture.handle); + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_handle); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + +/** + * Draws the emulated screens to the emulator window. + */ +void RendererOpenGL::DrawScreens() { glViewport(0, 0, resolution_width, resolution_height); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(program_id); + // Set projection matrix + std::array<GLfloat, 3*2> ortho_matrix = MakeOrthographicMatrix((float)resolution_width, (float)resolution_height); + glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); + // Bind texture in Texture Unit 0 glActiveTexture(GL_TEXTURE0); + glUniform1i(uniform_color_texture, 0); - glEnableVertexAttribArray(attrib_position); - glEnableVertexAttribArray(attrib_texcoord); - - for (int i = 0; i < 2; i++) { + const float max_width = std::max((float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenBottomWidth); + const float top_x = 0.5f * (max_width - VideoCore::kScreenTopWidth); + const float bottom_x = 0.5f * (max_width - VideoCore::kScreenBottomWidth); - ScreenInfo* current_screen = &screen_info[i]; - - glBindTexture(GL_TEXTURE_2D, current_screen->texture_id); - - // Set sampler on Texture Unit 0 - glUniform1i(sampler_id, 0); - - glBindBuffer(GL_ARRAY_BUFFER, current_screen->vertex_buffer_id); - - // Vertex buffer layout - const GLsizei stride = 5 * sizeof(GLfloat); - const GLvoid* uv_offset = (const GLvoid*)(3 * sizeof(GLfloat)); - - // Configure vertex buffer - glVertexAttribPointer(attrib_position, 3, GL_FLOAT, GL_FALSE, stride, NULL); - glVertexAttribPointer(attrib_texcoord, 2, GL_FLOAT, GL_FALSE, stride, uv_offset); - - // Draw screen - glDrawArrays(GL_TRIANGLES, 0, 6); - } - - glDisableVertexAttribArray(attrib_position); - glDisableVertexAttribArray(attrib_texcoord); + DrawSingleScreenRotated(textures[0], top_x, 0, + (float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenTopHeight); + DrawSingleScreenRotated(textures[1], bottom_x, (float)VideoCore::kScreenTopHeight, + (float)VideoCore::kScreenBottomWidth, (float)VideoCore::kScreenBottomHeight); m_current_frame++; } @@ -253,20 +238,8 @@ void RendererOpenGL::Init() { exit(-1); } - // Generate VAO - glGenVertexArrays(1, &vertex_array_id); - glBindVertexArray(vertex_array_id); - - glClearColor(1.0f, 1.0f, 1.0f, 0.0f); - glDisable(GL_DEPTH_TEST); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - // Initialize everything else - // -------------------------- - InitFramebuffer(); - NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); + InitOpenGLObjects(); } /// Shutdown the renderer diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index eac91df51..eed201a95 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -7,73 +7,50 @@ #include "generated/gl_3_2_core.h" #include "common/common.h" -#include "common/emu_window.h" - +#include "core/hw/gpu.h" #include "video_core/renderer_base.h" #include <array> -class RendererOpenGL : virtual public RendererBase { +class EmuWindow; + +class RendererOpenGL : public RendererBase { public: RendererOpenGL(); - ~RendererOpenGL(); + ~RendererOpenGL() override; /// Swap buffers (render frame) - void SwapBuffers(); - - /** - * Renders external framebuffer (XFB) - * @param src_rect Source rectangle in XFB to copy - * @param dst_rect Destination rectangle in output framebuffer to copy to - */ - void RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect); + void SwapBuffers() override; /** * Set the emulator window to use for renderer * @param window EmuWindow handle to emulator window to use for rendering */ - void SetWindow(EmuWindow* window); + void SetWindow(EmuWindow* window) override; /// Initialize the renderer - void Init(); + void Init() override; /// Shutdown the renderer - void ShutDown(); + void ShutDown() override; private: + /// Structure used for storing information about the textures for each 3DS screen + struct TextureInfo { + GLuint handle; + GLsizei width; + GLsizei height; + }; - /// Initialize the FBO - void InitFramebuffer(); - - // Blit the FBO to the OpenGL default framebuffer - void RenderFramebuffer(); - - /// Updates the framerate + void InitOpenGLObjects(); + void DrawScreens(); + void DrawSingleScreenRotated(const TextureInfo& texture, float x, float y, float w, float h); void UpdateFramerate(); - /// Structure used for storing information for rendering each 3DS screen - struct ScreenInfo { - // Properties - int width; - int height; - int stride; ///< Number of bytes between the coordinates (0,0) and (1,0) - - // OpenGL object IDs - GLuint texture_id; - GLuint vertex_buffer_id; - - // Temporary - u8* flipped_xfb_data; - }; - - /** - * Helper function to flip framebuffer from left-to-right to top-to-bottom - * @param raw_data Pointer to input raw framebuffer in V/RAM - * @param screen_info ScreenInfo structure with screen size and output buffer pointer - * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei - */ - void FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info); + // Loads framebuffer from emulated memory into the active OpenGL texture. + static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, + const TextureInfo& texture); EmuWindow* render_window; ///< Handle to render window u32 last_mode; ///< Last render mode @@ -81,22 +58,15 @@ private: int resolution_width; ///< Current resolution width int resolution_height; ///< Current resolution height - // OpenGL global object IDs - GLuint vertex_array_id; + // OpenGL object IDs + GLuint vertex_array_handle; + GLuint vertex_buffer_handle; GLuint program_id; - GLuint sampler_id; + std::array<TextureInfo, 2> textures; + // Shader uniform location indices + GLuint uniform_modelview_matrix; + GLuint uniform_color_texture; // Shader attribute input indices GLuint attrib_position; - GLuint attrib_texcoord; - - struct : std::array<ScreenInfo, 2> { - ScreenInfo& Top() { return (*this)[0]; } - ScreenInfo& Bottom() { return (*this)[1]; } - } screen_info; - - // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom - // as OpenGL expects them in a texture. There probably is a more efficient way of doing this: - u8 xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4]; - u8 xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4]; - + GLuint attrib_tex_coord; }; diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp index b94376ac1..c1848f923 100644 --- a/src/video_core/utils.cpp +++ b/src/video_core/utils.cpp @@ -8,6 +8,7 @@ #include "video_core/utils.h" namespace VideoCore { + /** * Dumps a texture to TGA * @param filename String filename to dump texture to @@ -16,29 +17,20 @@ namespace VideoCore { * @param raw_data Raw RGBA8 texture data to dump * @todo This should be moved to some general purpose/common code */ -void DumpTGA(std::string filename, int width, int height, u8* raw_data) { - TGAHeader hdr; - FILE* fout; - u8 r, g, b; - - memset(&hdr, 0, sizeof(hdr)); - hdr.datatypecode = 2; // uncompressed RGB - hdr.bitsperpixel = 24; // 24 bpp - hdr.width = width; - hdr.height = height; - - fout = fopen(filename.c_str(), "wb"); +void DumpTGA(std::string filename, short width, short height, u8* raw_data) { + TGAHeader hdr = {0, 0, 2, 0, 0, 0, 0, width, height, 24, 0}; + FILE* fout = fopen(filename.c_str(), "wb"); + fwrite(&hdr, sizeof(TGAHeader), 1, fout); - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - b = raw_data[(3 * (i * width)) + (3 * j) + 0]; - g = raw_data[(3 * (i * width)) + (3 * j) + 1]; - r = raw_data[(3 * (i * width)) + (3 * j) + 2]; - putc(b, fout); - putc(g, fout); - putc(r, fout); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + putc(raw_data[(3 * (y * width)) + (3 * x) + 0], fout); // b + putc(raw_data[(3 * (y * width)) + (3 * x) + 1], fout); // g + putc(raw_data[(3 * (y * width)) + (3 * x) + 2], fout); // r } } + fclose(fout); } } // namespace diff --git a/src/video_core/utils.h b/src/video_core/utils.h index 20d4ec9e0..9cb3d4d43 100644 --- a/src/video_core/utils.h +++ b/src/video_core/utils.h @@ -59,6 +59,6 @@ struct TGAHeader { * @param raw_data Raw RGBA8 texture data to dump * @todo This should be moved to some general purpose/common code */ -void DumpTGA(std::string filename, int width, int height, u8* raw_data); +void DumpTGA(std::string filename, short width, short height, u8* raw_data); } // namespace diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp index db8244317..96625791c 100644 --- a/src/video_core/vertex_shader.cpp +++ b/src/video_core/vertex_shader.cpp @@ -77,7 +77,7 @@ static void ProcessShaderCode(VertexShaderState& state) { : nullptr; const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; - const bool negate_src1 = swizzle.negate; + const bool negate_src1 = (swizzle.negate != 0); float24 src1[4] = { src1_[(int)swizzle.GetSelectorSrc1(0)], diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h index 847fdc450..607a8e803 100644 --- a/src/video_core/vertex_shader.h +++ b/src/video_core/vertex_shader.h @@ -225,7 +225,7 @@ union SwizzlePattern { } bool DestComponentEnabled(int i) const { - return (dest_mask & (0x8 >> i)); + return (dest_mask & (0x8 >> i)) != 0; } std::string SelectorToString(bool src2) const { diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 9aaff4917..c779771c5 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -21,13 +21,6 @@ EmuWindow* g_emu_window = NULL; ///< Frontend emulator window RendererBase* g_renderer = NULL; ///< Renderer plugin int g_current_frame = 0; -/// Start the video core -void Start() { - if (g_emu_window == NULL) { - ERROR_LOG(VIDEO, "VideoCore::Start called without calling Init()!"); - } -} - /// Initialize the video core void Init(EmuWindow* emu_window) { g_emu_window = emu_window; diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index d227b6aa4..609aac513 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h @@ -17,6 +17,10 @@ namespace VideoCore { // 3DS Video Constants // ------------------- +// NOTE: The LCDs actually rotate the image 90 degrees when displaying. Because of that the +// framebuffers in video memory are stored in column-major order and rendered sideways, causing +// the widths and heights of the framebuffers read by the LCD to be switched compared to the +// heights and widths of the screens listed here. static const int kScreenTopWidth = 400; ///< 3DS top screen width static const int kScreenTopHeight = 240; ///< 3DS top screen height static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width @@ -27,6 +31,7 @@ static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height extern RendererBase* g_renderer; ///< Renderer plugin extern int g_current_frame; ///< Current frame +extern EmuWindow* g_emu_window; ///< Emu window /// Start the video core void Start(); |