mirror of
https://github.com/simple64/simple64.git
synced 2026-11-14 09:28:42 +01:00
Merge commit '57999ac9b9d32775efc271e0edfed27b784ee1c6' as 'parallel-rsp'
This commit is contained in:
commit
d9155d3878
377 files changed
+137898
No files matched your search
Executable
+167
@@ -0,0 +1,167 @@
|
||||
# The style used for all options not specifically set in the configuration.
|
||||
BasedOnStyle: LLVM
|
||||
|
||||
# The extra indent or outdent of access modifiers, e.g. public:.
|
||||
AccessModifierOffset: -4
|
||||
|
||||
# If true, aligns escaped newlines as far left as possible. Otherwise puts them into the right-most column.
|
||||
AlignEscapedNewlinesLeft: true
|
||||
|
||||
# If true, aligns trailing comments.
|
||||
AlignTrailingComments: false
|
||||
|
||||
# Allow putting all parameters of a function declaration onto the next line even if BinPackParameters is false.
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
|
||||
# Allows contracting simple braced statements to a single line.
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
|
||||
# If true, short case labels will be contracted to a single line.
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
|
||||
# Dependent on the value, int f() { return 0; } can be put on a single line. Possible values: None, Inline, All.
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
|
||||
# If true, if (a) return; can be put on a single line.
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
|
||||
# If true, while (true) continue; can be put on a single line.
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
|
||||
# If true, always break after function definition return types.
|
||||
AlwaysBreakAfterDefinitionReturnType: false
|
||||
|
||||
# If true, always break before multiline string literals.
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
|
||||
# If true, always break after the template<...> of a template declaration.
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
|
||||
# If false, a function call's arguments will either be all on the same line or will have one line each.
|
||||
BinPackArguments: true
|
||||
|
||||
# If false, a function declaration's or function definition's parameters will either all be on the same line
|
||||
# or will have one line each.
|
||||
BinPackParameters: true
|
||||
|
||||
# The way to wrap binary operators. Possible values: None, NonAssignment, All.
|
||||
BreakBeforeBinaryOperators: None
|
||||
|
||||
# The brace breaking style to use. Possible values: Attach, Linux, Stroustrup, Allman, GNU.
|
||||
BreakBeforeBraces: Allman
|
||||
|
||||
# If true, ternary operators will be placed after line breaks.
|
||||
BreakBeforeTernaryOperators: false
|
||||
|
||||
# Always break constructor initializers before commas and align the commas with the colon.
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
|
||||
# The column limit. A column limit of 0 means that there is no column limit.
|
||||
ColumnLimit: 120
|
||||
|
||||
# A regular expression that describes comments with special meaning, which should not be split into lines or otherwise changed.
|
||||
CommentPragmas: '^ *'
|
||||
|
||||
# If the constructor initializers don't fit on a line, put each initializer on its own line.
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
|
||||
# The number of characters to use for indentation of constructor initializer lists.
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
|
||||
# Indent width for line continuations.
|
||||
ContinuationIndentWidth: 4
|
||||
|
||||
# If true, format braced lists as best suited for C++11 braced lists.
|
||||
Cpp11BracedListStyle: false
|
||||
|
||||
# Disables formatting at all.
|
||||
DisableFormat: false
|
||||
|
||||
# A vector of macros that should be interpreted as foreach loops instead of as function calls.
|
||||
#ForEachMacros: ''
|
||||
|
||||
# Indent case labels one level from the switch statement.
|
||||
# When false, use the same indentation level as for the switch statement.
|
||||
# Switch statement body is always indented one level more than case labels.
|
||||
IndentCaseLabels: false
|
||||
|
||||
# The number of columns to use for indentation.
|
||||
IndentWidth: 4
|
||||
|
||||
# Indent if a function definition or declaration is wrapped after the type.
|
||||
IndentWrappedFunctionNames: false
|
||||
|
||||
# If true, empty lines at the start of blocks are kept.
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
|
||||
# Language, this format style is targeted at. Possible values: None, Cpp, Java, JavaScript, Proto.
|
||||
Language: Cpp
|
||||
|
||||
# The maximum number of consecutive empty lines to keep.
|
||||
MaxEmptyLinesToKeep: 1
|
||||
|
||||
# The indentation used for namespaces. Possible values: None, Inner, All.
|
||||
NamespaceIndentation: None
|
||||
|
||||
# The penalty for breaking a function call after "call(".
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
|
||||
# The penalty for each line break introduced inside a comment.
|
||||
PenaltyBreakComment: 300
|
||||
|
||||
# The penalty for breaking before the first <<.
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
|
||||
# The penalty for each line break introduced inside a string literal.
|
||||
PenaltyBreakString: 1000
|
||||
|
||||
# The penalty for each character outside of the column limit.
|
||||
PenaltyExcessCharacter: 1000000
|
||||
|
||||
# Penalty for putting the return type of a function onto its own line.
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000000000
|
||||
|
||||
# Pointer and reference alignment style. Possible values: Left, Right, Middle.
|
||||
PointerAlignment: Right
|
||||
|
||||
# If true, a space may be inserted after C style casts.
|
||||
SpaceAfterCStyleCast: false
|
||||
|
||||
# If false, spaces will be removed before assignment operators.
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
|
||||
# Defines in which cases to put a space before opening parentheses. Possible values: Never, ControlStatements, Always.
|
||||
SpaceBeforeParens: ControlStatements
|
||||
|
||||
# If true, spaces may be inserted into '()'.
|
||||
SpaceInEmptyParentheses: false
|
||||
|
||||
# The number of spaces before trailing line comments (// - comments).
|
||||
SpacesBeforeTrailingComments: 1
|
||||
|
||||
# If true, spaces will be inserted after '<' and before '>' in template argument lists.
|
||||
SpacesInAngles: false
|
||||
|
||||
# If true, spaces may be inserted into C style casts.
|
||||
SpacesInCStyleCastParentheses: false
|
||||
|
||||
# If true, spaces are inserted inside container literals (e.g. ObjC and Javascript array and dict literals).
|
||||
SpacesInContainerLiterals: false
|
||||
|
||||
# If true, spaces will be inserted after '(' and before ')'.
|
||||
SpacesInParentheses: false
|
||||
|
||||
# If true, spaces will be inserted after '[' and befor']'.
|
||||
SpacesInSquareBrackets: false
|
||||
|
||||
# Format compatible with this standard, e.g. use A<A<int> > instead of A<A<int>> for LS_Cpp03. Possible values: Cpp03, Cpp11, Auto.
|
||||
Standard: Cpp11
|
||||
|
||||
# The number of columns used for tab stops.
|
||||
TabWidth: 4
|
||||
|
||||
# The way to use tab characters in the resulting file. Possible values: Never, ForIndentation, Always.
|
||||
UseTab: ForIndentation
|
||||
|
||||
# Do not reflow comments
|
||||
ReflowComments: false
|
||||
@@ -0,0 +1,8 @@
|
||||
*.o
|
||||
*.d
|
||||
*.bin
|
||||
*.elf
|
||||
/cmake-build-*
|
||||
/.idea
|
||||
*.iml
|
||||
/build-*
|
||||
@@ -0,0 +1,99 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
project(parallel-rsp LANGUAGES CXX C)
|
||||
|
||||
|
||||
set(NAME_PLUGIN_M64P "mupen64plus-rsp-parallel")
|
||||
|
||||
include_directories(../mupen64plus-core/src/api)
|
||||
add_definitions(-DM64P_PLUGIN_API)
|
||||
add_definitions(-DPARALLEL_INTEGRATION)
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX OR (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang"))
|
||||
set(PARALLEL_RSP_CXX_FLAGS -Wall -Wextra -Wno-missing-field-initializers -Wno-empty-body -ffast-math -Wno-unused-parameter)
|
||||
elseif (MSVC)
|
||||
set(PARALLEL_RSP_CXX_FLAGS /D_CRT_SECURE_NO_WARNINGS /wd4267 /wd4244 /wd4309 /wd4005 /MP /DNOMINMAX)
|
||||
endif()
|
||||
|
||||
add_library(${NAME_PLUGIN_M64P} SHARED
|
||||
# main.cpp
|
||||
parallel.cpp
|
||||
# debug_rsp.cpp
|
||||
rsp/vfunctions.cpp
|
||||
rsp_jit.cpp rsp_jit.hpp
|
||||
jit_allocator.cpp jit_allocator.hpp
|
||||
rsp_disasm.cpp rsp_disasm.hpp
|
||||
rsp/ls.cpp rsp/pipeline.h
|
||||
rsp/reciprocal.cpp rsp/reciprocal.h
|
||||
rsp_1.1.h
|
||||
rsp/cp0.cpp rsp/cp2.cpp
|
||||
arch/simd/rsp/rsp_core.cpp
|
||||
arch/simd/rsp/clamp.h
|
||||
arch/simd/rsp/rsp_common.h
|
||||
arch/simd/rsp/SSE2NEON.h
|
||||
arch/simd/rsp/rsp_impl.h
|
||||
arch/simd/rsp/vcr.h
|
||||
arch/simd/rsp/vabs.h
|
||||
arch/simd/rsp/vadd.h
|
||||
arch/simd/rsp/vaddc.h
|
||||
arch/simd/rsp/vand.h
|
||||
arch/simd/rsp/vch.h
|
||||
arch/simd/rsp/vcl.h
|
||||
arch/simd/rsp/vcr.h
|
||||
arch/simd/rsp/vcmp.h
|
||||
arch/simd/rsp/vdivh.h
|
||||
arch/simd/rsp/vmac.h
|
||||
arch/simd/rsp/vmov.h
|
||||
arch/simd/rsp/vmrg.h
|
||||
arch/simd/rsp/vmudh.h
|
||||
arch/simd/rsp/vmul.h
|
||||
arch/simd/rsp/vmull.h
|
||||
arch/simd/rsp/vmulh.h
|
||||
arch/simd/rsp/vmuln.h
|
||||
arch/simd/rsp/vor.h
|
||||
arch/simd/rsp/vrcpsq.h
|
||||
arch/simd/rsp/vrsq.h
|
||||
arch/simd/rsp/vsub.h
|
||||
arch/simd/rsp/vsubc.h
|
||||
arch/simd/rsp/vxor.h
|
||||
arch/simd/rsp/vmulm.h)
|
||||
|
||||
option(PARALLEL_RSP_DEBUG_JIT "Enable the debug JIT." OFF)
|
||||
|
||||
if (PARALLEL_RSP_DEBUG_JIT)
|
||||
if (ANDROID)
|
||||
message("Android does not support debug JIT. Disabling it.")
|
||||
elseif (NOT WIN32)
|
||||
target_sources(${NAME_PLUGIN_M64P} PRIVATE debug_rsp.cpp debug_rsp.hpp debug_jit.cpp debug_jit.hpp)
|
||||
target_compile_definitions(${NAME_PLUGIN_M64P} PUBLIC PARALLEL_RSP_DEBUG_JIT)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_target_properties(${NAME_PLUGIN_M64P} PROPERTIES PREFIX "")
|
||||
target_include_directories(${NAME_PLUGIN_M64P} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(${NAME_PLUGIN_M64P} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/arch/simd/rsp)
|
||||
target_include_directories(${NAME_PLUGIN_M64P} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/api)
|
||||
target_compile_options(${NAME_PLUGIN_M64P} PRIVATE ${PARALLEL_RSP_CXX_FLAGS})
|
||||
|
||||
option(PARALLEL_RSP_BAKED_LIGHTNING "Use built-in Lightning." ON)
|
||||
|
||||
target_compile_definitions(${NAME_PLUGIN_M64P} PUBLIC PARALLEL_RSP_LIGHTNING)
|
||||
if (PARALLEL_RSP_BAKED_LIGHTNING)
|
||||
add_library(lightning STATIC
|
||||
lightning/lib/jit_disasm.c
|
||||
lightning/lib/jit_memory.c
|
||||
lightning/lib/jit_names.c
|
||||
lightning/lib/jit_note.c
|
||||
lightning/lib/jit_print.c
|
||||
lightning/lib/jit_size.c
|
||||
lightning/lib/lightning.c)
|
||||
set_property(TARGET lightning PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
target_include_directories(lightning PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/lightning/include)
|
||||
if (WIN32)
|
||||
target_sources(lightning PRIVATE win32/mman/sys/mman.c)
|
||||
target_include_directories(lightning PRIVATE win32/mman)
|
||||
endif()
|
||||
endif()
|
||||
target_link_libraries(${NAME_PLUGIN_M64P} PUBLIC lightning)
|
||||
@@ -0,0 +1,13 @@
|
||||
Written by Themaister.
|
||||
|
||||
The code is heavily reliant on MarathonMan's CEN64 RSP implementation, as well as CXD4's RSP implementation.
|
||||
|
||||
MIPS core: Rewritten from scratch
|
||||
CP0: Near copy-pasta from CEN64
|
||||
CP2: Near copy-pasta from CEN64
|
||||
LS pipe: Near copy-pasta from CXD4
|
||||
Mupen64plus glue code: Reused most of CXD4.
|
||||
Lightning jitter interface: Written from scratch
|
||||
|
||||
The plugin's focus is to support dynamic recompilation for performance,
|
||||
instead of being pure interpreters as CEN64 and CXD4's implementations are.
|
||||
@@ -0,0 +1,16 @@
|
||||
==============
|
||||
parallel-rsp
|
||||
==============
|
||||
|
||||
This project is dual licensed under
|
||||
|
||||
MIT (LICENSE.MIT)
|
||||
|
||||
or
|
||||
|
||||
LGPLv3 (LICENSE.LESSER)
|
||||
|
||||
If statically linking against the GNU Lightning project (lightning/),
|
||||
note that Lightning is dual-licensed as GPLv3 or LGPLv3.
|
||||
parallel-rsp can be configured to dynamically link against Lightning or not link against Lightning at all.
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -0,0 +1,20 @@
|
||||
Copyright (c) 2020 Hans-Kristian Arntzen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
RSP_FUZZ="$1"
|
||||
|
||||
adb push "$RSP_FUZZ" /data/local/tmp/rsp-vu-fuzzer >/dev/null || exit 1
|
||||
adb shell chmod +x /data/local/tmp/rsp-vu-fuzzer >/dev/null || exit 1
|
||||
adb shell /data/local/tmp/rsp-vu-fuzzer || exit 1
|
||||
adb shell rm /data/local/tmp/rsp-vu-fuzzer || exit 1
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
RSP_RUNNER="$1"
|
||||
RSP_BINFOLDER="$2"
|
||||
TEST_NAME="$3"
|
||||
|
||||
adb push "$RSP_RUNNER" /data/local/tmp/rsp-runner >/dev/null || exit 1
|
||||
adb shell chmod +x /data/local/tmp/rsp-runner >/dev/null || exit 1
|
||||
adb push "$RSP_BINFOLDER"/"$TEST_NAME".global.bin /data/local/tmp/ >/dev/null || exit 1
|
||||
adb push "$RSP_BINFOLDER"/"$TEST_NAME".bin /data/local/tmp/ >/dev/null || exit 1
|
||||
adb shell /data/local/tmp/rsp-runner /data/local/tmp/"$TEST_NAME".global.bin /data/local/tmp/"$TEST_NAME".bin || exit 1
|
||||
adb shell rm /data/local/tmp/rsp-runner >/dev/null || exit 1
|
||||
adb shell rm /data/local/tmp/"$TEST_NAME".global.bin /data/local/tmp/"$TEST_NAME".bin >/dev/null || exit 1
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// arch/x86_64/rsp/clamp.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_sclamp_acc_tomd(__m128i acc_md, __m128i acc_hi)
|
||||
{
|
||||
__m128i l = _mm_unpacklo_epi16(acc_md, acc_hi);
|
||||
__m128i h = _mm_unpackhi_epi16(acc_md, acc_hi);
|
||||
return _mm_packs_epi32(l, h);
|
||||
}
|
||||
|
||||
static inline __m128i rsp_uclamp_acc(__m128i val, __m128i acc_md, __m128i acc_hi, __m128i zero)
|
||||
{
|
||||
__m128i clamp_mask, clamped_val;
|
||||
__m128i hi_sign_check, md_sign_check;
|
||||
__m128i md_negative, hi_negative;
|
||||
__m128i tmp;
|
||||
|
||||
hi_negative = _mm_srai_epi16(acc_hi, 15);
|
||||
md_negative = _mm_srai_epi16(acc_md, 15);
|
||||
|
||||
// We don't have to clamp if the HI part of the
|
||||
// accumulator is sign-extended down to the MD part.
|
||||
hi_sign_check = _mm_cmpeq_epi16(hi_negative, acc_hi);
|
||||
md_sign_check = _mm_cmpeq_epi16(hi_negative, md_negative);
|
||||
clamp_mask = _mm_and_si128(md_sign_check, hi_sign_check);
|
||||
|
||||
// Generate the value in the event we need to clamp.
|
||||
// * hi_negative, mid_sign => xxxx
|
||||
// * hi_negative, !mid_sign => 0000
|
||||
// * !hi_negative, mid_sign => FFFF
|
||||
// * !hi_negative, !mid_sign => xxxx
|
||||
clamped_val = _mm_cmpeq_epi16(hi_negative, zero);
|
||||
|
||||
#ifndef __SSE4_1__
|
||||
tmp = _mm_and_si128(clamp_mask, val);
|
||||
val = _mm_andnot_si128(clamp_mask, clamped_val);
|
||||
return _mm_or_si128(val, tmp);
|
||||
#else
|
||||
return _mm_blendv_epi8(clamped_val, val, clamp_mask);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
//
|
||||
// arch/x86_64/rsp/rsp.h
|
||||
//
|
||||
// Extern declarations for host RSP functions.
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
#ifndef __arch_rsp_h__
|
||||
#define __arch_rsp_h__
|
||||
|
||||
#ifdef __ARM_NEON
|
||||
#define __SSSE3__
|
||||
#include "SSE2NEON.h"
|
||||
#elif defined(__SSE4_2__)
|
||||
#include <nmmintrin.h>
|
||||
#elif defined(__SSE4_1__)
|
||||
#include <smmintrin.h>
|
||||
#elif defined(__SSSE3__)
|
||||
#include <tmmintrin.h>
|
||||
#elif defined(__SSE3__)
|
||||
#include <pmmintrin.h>
|
||||
#else
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef __m128i rsp_vect_t;
|
||||
|
||||
namespace RSP
|
||||
{
|
||||
struct CPUState;
|
||||
}
|
||||
|
||||
// Loads and shuffles a 16x8 vector according to element.
|
||||
#ifdef __SSSE3__
|
||||
extern const uint16_t shuffle_keys[16][8];
|
||||
|
||||
static inline __m128i rsp_vect_load_and_shuffle_operand(const uint16_t *src, unsigned element)
|
||||
{
|
||||
__m128i operand = _mm_load_si128((__m128i *)src);
|
||||
__m128i key = _mm_load_si128((__m128i *)shuffle_keys[element]);
|
||||
|
||||
return _mm_shuffle_epi8(operand, key);
|
||||
}
|
||||
#else
|
||||
__m128i rsp_vect_load_and_shuffle_operand(const uint16_t *src, unsigned element);
|
||||
#endif
|
||||
|
||||
// Loads a vector without shuffling its elements.
|
||||
static inline __m128i rsp_vect_load_unshuffled_operand(const uint16_t *src)
|
||||
{
|
||||
return _mm_load_si128((__m128i *)src);
|
||||
}
|
||||
|
||||
// Writes an operand back to memory.
|
||||
static inline void rsp_vect_write_operand(uint16_t *dest, __m128i src)
|
||||
{
|
||||
_mm_store_si128((__m128i *)dest, src);
|
||||
}
|
||||
|
||||
static inline __m128i read_acc_lo(const uint16_t *acc)
|
||||
{
|
||||
return rsp_vect_load_unshuffled_operand(acc + 16);
|
||||
}
|
||||
static inline __m128i read_acc_md(const uint16_t *acc)
|
||||
{
|
||||
return rsp_vect_load_unshuffled_operand(acc + 8);
|
||||
}
|
||||
static inline __m128i read_acc_hi(const uint16_t *acc)
|
||||
{
|
||||
return rsp_vect_load_unshuffled_operand(acc);
|
||||
}
|
||||
static inline __m128i read_vcc_lo(const uint16_t *vcc)
|
||||
{
|
||||
return rsp_vect_load_unshuffled_operand(vcc + 8);
|
||||
}
|
||||
static inline __m128i read_vcc_hi(const uint16_t *vcc)
|
||||
{
|
||||
return rsp_vect_load_unshuffled_operand(vcc);
|
||||
}
|
||||
static inline __m128i read_vco_lo(const uint16_t *vco)
|
||||
{
|
||||
return rsp_vect_load_unshuffled_operand(vco + 8);
|
||||
}
|
||||
static inline __m128i read_vco_hi(const uint16_t *vco)
|
||||
{
|
||||
return rsp_vect_load_unshuffled_operand(vco);
|
||||
}
|
||||
static inline __m128i read_vce(const uint16_t *vce)
|
||||
{
|
||||
return rsp_vect_load_unshuffled_operand(vce + 8);
|
||||
}
|
||||
static inline void write_acc_lo(uint16_t *acc, __m128i acc_lo)
|
||||
{
|
||||
rsp_vect_write_operand(acc + 16, acc_lo);
|
||||
}
|
||||
static inline void write_acc_md(uint16_t *acc, __m128i acc_md)
|
||||
{
|
||||
rsp_vect_write_operand(acc + 8, acc_md);
|
||||
}
|
||||
static inline void write_acc_hi(uint16_t *acc, __m128i acc_hi)
|
||||
{
|
||||
rsp_vect_write_operand(acc, acc_hi);
|
||||
}
|
||||
static inline void write_vcc_lo(uint16_t *vcc, __m128i vcc_lo)
|
||||
{
|
||||
rsp_vect_write_operand(vcc + 8, vcc_lo);
|
||||
}
|
||||
static inline void write_vcc_hi(uint16_t *vcc, __m128i vcc_hi)
|
||||
{
|
||||
rsp_vect_write_operand(vcc, vcc_hi);
|
||||
}
|
||||
static inline void write_vco_lo(uint16_t *vco, __m128i vco_lo)
|
||||
{
|
||||
rsp_vect_write_operand(vco + 8, vco_lo);
|
||||
}
|
||||
static inline void write_vco_hi(uint16_t *vco, __m128i vco_hi)
|
||||
{
|
||||
rsp_vect_write_operand(vco, vco_hi);
|
||||
}
|
||||
static inline void write_vce(uint16_t *vce, __m128i vce_r)
|
||||
{
|
||||
rsp_vect_write_operand(vce + 8, vce_r);
|
||||
}
|
||||
|
||||
// Returns scalar bitmasks for VCO/VCC/VCE.
|
||||
static inline int16_t rsp_get_flags(const uint16_t *flags)
|
||||
{
|
||||
return (int16_t)_mm_movemask_epi8(
|
||||
_mm_packs_epi16(_mm_load_si128((__m128i *)(flags + 8)), _mm_load_si128((__m128i *)(flags + 0))));
|
||||
}
|
||||
|
||||
void rsp_set_flags(uint16_t *flags, uint16_t rt);
|
||||
|
||||
// Zeroes out a vector register.
|
||||
static inline __m128i rsp_vzero(void)
|
||||
{
|
||||
return _mm_setzero_si128();
|
||||
}
|
||||
|
||||
extern const uint16_t vdiv_mask_table[8][8];
|
||||
|
||||
#define HES(x) ((x) ^ 2)
|
||||
#define BES(x) ((x) ^ 3)
|
||||
#define MES(x) ((x) ^ 1)
|
||||
|
||||
#define READ_MEM_U8(mem, addr) (reinterpret_cast<const uint8_t *>(mem)[BES(addr)])
|
||||
#define READ_MEM_U16(mem, addr) (reinterpret_cast<const uint16_t *>(mem)[HES(addr) >> 1])
|
||||
#define READ_MEM_U32(mem, addr) (reinterpret_cast<const uint32_t *>(mem)[addr >> 2])
|
||||
|
||||
#define WRITE_MEM_U8(mem, addr, data) (reinterpret_cast<uint8_t *>(mem)[BES(addr)] = data)
|
||||
#define WRITE_MEM_U16(mem, addr, data) (reinterpret_cast<uint16_t *>(mem)[HES(addr) >> 1] = data)
|
||||
#define WRITE_MEM_U32(mem, addr, data) (reinterpret_cast<uint32_t *>(mem)[addr >> 2] = data)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,603 @@
|
||||
//
|
||||
// arch/x86_64/rsp/rsp.c
|
||||
//
|
||||
// Declarations for host RSP functions.
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
#include "../../../state.hpp"
|
||||
#include "rsp_common.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __SSSE3__
|
||||
//
|
||||
// This table is used to "shuffle" the RSP vector after loading it.
|
||||
//
|
||||
alignas(64) const uint16_t shuffle_keys[16][8] = {
|
||||
/* -- */ { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E },
|
||||
/* -- */ { 0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E },
|
||||
|
||||
/* 0q */ { 0x0100, 0x0100, 0x0504, 0x0504, 0x0908, 0x0908, 0x0D0C, 0x0D0C },
|
||||
/* 1q */ { 0x0302, 0x0302, 0x0706, 0x0706, 0x0B0A, 0x0B0A, 0x0F0E, 0x0F0E },
|
||||
|
||||
/* 0h */ { 0x0100, 0x0100, 0x0100, 0x0100, 0x0908, 0x0908, 0x0908, 0x0908 },
|
||||
/* 1h */ { 0x0302, 0x0302, 0x0302, 0x0302, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A },
|
||||
/* 2h */ { 0x0504, 0x0504, 0x0504, 0x0504, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C },
|
||||
/* 3h */ { 0x0706, 0x0706, 0x0706, 0x0706, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E },
|
||||
|
||||
/* 0w */ { 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100 },
|
||||
/* 1w */ { 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302, 0x0302 },
|
||||
/* 2w */ { 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504, 0x0504 },
|
||||
/* 3w */ { 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706, 0x0706 },
|
||||
/* 4w */ { 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908, 0x0908 },
|
||||
/* 5w */ { 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A, 0x0B0A },
|
||||
/* 6w */ { 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C, 0x0D0C },
|
||||
/* 7w */ { 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E, 0x0F0E },
|
||||
};
|
||||
#endif
|
||||
|
||||
//
|
||||
// These tables are used to shift data loaded from DMEM.
|
||||
// In addition to shifting, they also take into account that
|
||||
// DMEM uses big-endian byte ordering, whereas vectors are
|
||||
// 2-byte little-endian.
|
||||
//
|
||||
|
||||
// Shift left LUT; shifts in zeros from the right, one byte at a time.
|
||||
alignas(64) static const uint16_t sll_b2l_keys[16][8] = {
|
||||
{ 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
|
||||
{ 0x8000, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E },
|
||||
{ 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
|
||||
{ 0x8080, 0x8000, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C },
|
||||
|
||||
{ 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
|
||||
{ 0x8080, 0x8080, 0x8000, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8000, 0x0102, 0x0304, 0x0506, 0x0708 },
|
||||
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8000, 0x0102, 0x0304, 0x0506 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8000, 0x0102, 0x0304 },
|
||||
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8000, 0x0102 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8000 },
|
||||
};
|
||||
|
||||
// Shift left LUT; shirts low order to high order, inserting 0x00s.
|
||||
alignas(64) static const uint16_t sll_l2b_keys[16][8] = {
|
||||
{ 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
|
||||
{ 0x0180, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0E0C },
|
||||
{ 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
|
||||
{ 0x8080, 0x0180, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A },
|
||||
|
||||
{ 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
|
||||
{ 0x8080, 0x8080, 0x0180, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x0180, 0x0300, 0x0502, 0x0704, 0x0906 },
|
||||
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405, 0x0607 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x0180, 0x0300, 0x0502, 0x0704 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203, 0x0405 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0180, 0x0300, 0x0502 },
|
||||
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001, 0x0203 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0180, 0x0300 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0001 },
|
||||
{ 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x0180 },
|
||||
};
|
||||
|
||||
// Shift right LUT; shifts in zeros from the left, one byte at a time.
|
||||
alignas(64) static const uint16_t srl_b2l_keys[16][8] = {
|
||||
{ 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
|
||||
{ 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F80 },
|
||||
{ 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x8080 },
|
||||
{ 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F80, 0x8080 },
|
||||
|
||||
{ 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x8080, 0x8080 },
|
||||
{ 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F80, 0x8080, 0x8080 },
|
||||
{ 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x8080, 0x8080, 0x8080 },
|
||||
{ 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F80, 0x8080, 0x8080, 0x8080 },
|
||||
|
||||
{ 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x8080, 0x8080, 0x8080, 0x8080 },
|
||||
{ 0x090A, 0x0B0C, 0x0D0E, 0x0F80, 0x8080, 0x8080, 0x8080, 0x8080 },
|
||||
{ 0x0A0B, 0x0C0D, 0x0E0F, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
|
||||
{ 0x0B0C, 0x0D0E, 0x0F80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
|
||||
|
||||
{ 0x0C0D, 0x0E0F, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
|
||||
{ 0x0D0E, 0x0F80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
|
||||
{ 0x0E0F, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
|
||||
{ 0x0F80, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080, 0x8080 },
|
||||
};
|
||||
|
||||
alignas(64) static const uint16_t ror_b2l_keys[16][8] = {
|
||||
{ 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
|
||||
{ 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F00 },
|
||||
{ 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001 },
|
||||
{ 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F00, 0x0102 },
|
||||
|
||||
{ 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203 },
|
||||
{ 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F00, 0x0102, 0x0304 },
|
||||
{ 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405 },
|
||||
{ 0x0708, 0x090A, 0x0B0C, 0x0D0E, 0x0F00, 0x0102, 0x0304, 0x0506 },
|
||||
|
||||
{ 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607 },
|
||||
{ 0x090A, 0x0B0C, 0x0D0E, 0x0F00, 0x0102, 0x0304, 0x0506, 0x0708 },
|
||||
{ 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
|
||||
{ 0x0B0C, 0x0D0E, 0x0F00, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A },
|
||||
|
||||
{ 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
|
||||
{ 0x0D0E, 0x0F00, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C },
|
||||
{ 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
|
||||
{ 0x0F00, 0x0102, 0x0304, 0x0506, 0x0708, 0x090A, 0x0B0C, 0x0D0E },
|
||||
};
|
||||
|
||||
// Rotate left LUT; rotates high order bytes back to low order.
|
||||
alignas(64) static const uint16_t rol_l2b_keys[16][8] = {
|
||||
{ 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
|
||||
{ 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C },
|
||||
{ 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
|
||||
{ 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A },
|
||||
|
||||
{ 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
|
||||
{ 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08 },
|
||||
{ 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
|
||||
{ 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906 },
|
||||
|
||||
{ 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607 },
|
||||
{ 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704 },
|
||||
{ 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405 },
|
||||
{ 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502 },
|
||||
|
||||
{ 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203 },
|
||||
{ 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300 },
|
||||
{ 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001 },
|
||||
{ 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E },
|
||||
};
|
||||
|
||||
// Rotate right LUT; rotates high order bytes back to low order.
|
||||
alignas(64) static const uint16_t ror_l2b_keys[16][8] = {
|
||||
{ 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F },
|
||||
{ 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E },
|
||||
{ 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001 },
|
||||
{ 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300 },
|
||||
|
||||
{ 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203 },
|
||||
{ 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502 },
|
||||
{ 0x0607, 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405 },
|
||||
{ 0x0906, 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704 },
|
||||
|
||||
{ 0x0809, 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607 },
|
||||
{ 0x0B08, 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906 },
|
||||
{ 0x0A0B, 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809 },
|
||||
{ 0x0D0A, 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08 },
|
||||
|
||||
{ 0x0C0D, 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B },
|
||||
{ 0x0F0C, 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A },
|
||||
{ 0x0E0F, 0x0001, 0x0203, 0x0405, 0x0607, 0x0809, 0x0A0B, 0x0C0D },
|
||||
{ 0x010E, 0x0300, 0x0502, 0x0704, 0x0906, 0x0B08, 0x0D0A, 0x0F0C },
|
||||
};
|
||||
|
||||
#ifndef __SSSE3__
|
||||
static inline __m128i sse2_pshufb_loop8(__m128i v, const uint8_t *keys)
|
||||
{
|
||||
alignas(16) uint8_t temp[(0x80 | 128) + 1];
|
||||
unsigned j;
|
||||
|
||||
_mm_store_si128((__m128i *)temp, v);
|
||||
temp[0x80] = 0;
|
||||
|
||||
#if 0
|
||||
for (j = 0; j < 16; j++)
|
||||
temp[j + 16] = temp[keys[j]];
|
||||
#else
|
||||
for (j = 0; j < 16; j += 4)
|
||||
{
|
||||
temp[j + 16] = temp[keys[j + 0]];
|
||||
temp[j + 17] = temp[keys[j + 1]];
|
||||
temp[j + 18] = temp[keys[j + 2]];
|
||||
temp[j + 19] = temp[keys[j + 3]];
|
||||
}
|
||||
#endif
|
||||
|
||||
return _mm_load_si128(((__m128i *)temp) + 1);
|
||||
}
|
||||
static inline __m128i sse2_pshufb(__m128i v, const uint16_t *keys)
|
||||
{
|
||||
union {
|
||||
const uint16_t *k16;
|
||||
const uint8_t *k8;
|
||||
} x;
|
||||
x.k16 = keys;
|
||||
return sse2_pshufb_loop8(v, x.k8);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Uses a LUT to populate flag registers.
|
||||
void rsp_set_flags(uint16_t *flags, uint16_t rt)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
static const uint16_t array[16][4] = {
|
||||
{ 0x0000, 0x0000, 0x0000, 0x0000 }, { 0xFFFF, 0x0000, 0x0000, 0x0000 }, { 0x0000, 0xFFFF, 0x0000, 0x0000 },
|
||||
{ 0xFFFF, 0xFFFF, 0x0000, 0x0000 }, { 0x0000, 0x0000, 0xFFFF, 0x0000 }, { 0xFFFF, 0x0000, 0xFFFF, 0x0000 },
|
||||
{ 0x0000, 0xFFFF, 0xFFFF, 0x0000 }, { 0xFFFF, 0xFFFF, 0xFFFF, 0x0000 }, { 0x0000, 0x0000, 0x0000, 0xFFFF },
|
||||
{ 0xFFFF, 0x0000, 0x0000, 0xFFFF }, { 0x0000, 0xFFFF, 0x0000, 0xFFFF }, { 0xFFFF, 0xFFFF, 0x0000, 0xFFFF },
|
||||
{ 0x0000, 0x0000, 0xFFFF, 0xFFFF }, { 0xFFFF, 0x0000, 0xFFFF, 0xFFFF }, { 0x0000, 0xFFFF, 0xFFFF, 0xFFFF },
|
||||
{ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF },
|
||||
};
|
||||
|
||||
for (i = 0; i < 2; i++, rt >>= 4)
|
||||
memcpy(flags + 8 + i * 4, array[rt & 0xF], sizeof(array[0]));
|
||||
|
||||
for (i = 0; i < 2; i++, rt >>= 4)
|
||||
memcpy(flags + 0 + i * 4, array[rt & 0xF], sizeof(array[0]));
|
||||
}
|
||||
|
||||
#ifndef __SSSE3__
|
||||
__m128i rsp_vect_load_and_shuffle_operand(const uint16_t *src, unsigned element)
|
||||
{
|
||||
__m128i v;
|
||||
|
||||
switch (element)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
v = _mm_load_si128((__m128i *)src);
|
||||
return v;
|
||||
|
||||
// element => 0q
|
||||
case 2:
|
||||
v = _mm_load_si128((__m128i *)src);
|
||||
v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(2, 2, 0, 0));
|
||||
return v;
|
||||
|
||||
// element => 1q
|
||||
case 3:
|
||||
v = _mm_load_si128((__m128i *)src);
|
||||
v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(3, 3, 1, 1));
|
||||
v = _mm_shufflehi_epi16(v, _MM_SHUFFLE(3, 3, 1, 1));
|
||||
return v;
|
||||
|
||||
// element => 0h ... 3h
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
__asm__("" : "=x"(v)); /* Do not remove. */
|
||||
v = _mm_insert_epi16(v, src[element - 4], 0);
|
||||
v = _mm_insert_epi16(v, src[element - 0], 1);
|
||||
v = _mm_shufflelo_epi16(v, _MM_SHUFFLE(1, 1, 0, 0));
|
||||
v = _mm_shuffle_epi32(v, _MM_SHUFFLE(1, 1, 0, 0));
|
||||
return v;
|
||||
|
||||
// element => 0w ... 7w
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
__asm__("" : "=x"(v)); /* Do not remove. */
|
||||
v = _mm_insert_epi16(v, src[element - 8], 0);
|
||||
v = _mm_unpacklo_epi16(v, v);
|
||||
v = _mm_shuffle_epi32(v, _MM_SHUFFLE(0, 0, 0, 0));
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
__builtin_unreachable();
|
||||
#else
|
||||
__builtin_trap();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// SSSE3+ accelerated loads for group I. Byteswap big-endian to 2-byte
|
||||
// little-endian vector. Start at vector element offset, discarding any
|
||||
// wraparound as necessary.
|
||||
//
|
||||
// TODO: Reverse-engineer what happens when loads to vector elements must
|
||||
// wraparound. Do we just discard the data, as below, or does the
|
||||
// data effectively get rotated around the edge of the vector?
|
||||
//
|
||||
void rsp_vload_group1(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
|
||||
rsp_vect_t dqm)
|
||||
{
|
||||
__m128i data;
|
||||
|
||||
unsigned offset = addr & 0x7;
|
||||
unsigned ror = offset - element;
|
||||
|
||||
// Always load in 8-byte chunks to emulate wraparound.
|
||||
if (offset)
|
||||
{
|
||||
uint32_t aligned_addr_lo = addr & ~0x7;
|
||||
uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF;
|
||||
__m128i temp;
|
||||
|
||||
data = _mm_loadl_epi64((__m128i *)(rsp->dmem + aligned_addr_lo));
|
||||
temp = _mm_loadl_epi64((__m128i *)(rsp->dmem + aligned_addr_hi));
|
||||
data = _mm_unpacklo_epi64(data, temp);
|
||||
}
|
||||
|
||||
else
|
||||
data = _mm_loadl_epi64((__m128i *)(rsp->dmem + addr));
|
||||
|
||||
// Shift the DQM up to the point where we mux in the data.
|
||||
#ifndef __SSSE3__
|
||||
dqm = sse2_pshufb(dqm, sll_b2l_keys[element]);
|
||||
#else
|
||||
__m128i ekey = _mm_load_si128((__m128i *)(sll_b2l_keys[element]));
|
||||
dqm = _mm_shuffle_epi8(dqm, ekey);
|
||||
#endif
|
||||
|
||||
// Align the data to the DQM so we can mask it in.
|
||||
#ifndef __SSSE3__
|
||||
data = sse2_pshufb(data, ror_b2l_keys[ror & 0xF]);
|
||||
#else
|
||||
ekey = _mm_load_si128((__m128i *)(ror_b2l_keys[ror & 0xF]));
|
||||
data = _mm_shuffle_epi8(data, ekey);
|
||||
#endif
|
||||
|
||||
// Mask and mux in the data.
|
||||
#ifdef __SSE4_1__
|
||||
reg = _mm_blendv_epi8(reg, data, dqm);
|
||||
#else
|
||||
data = _mm_and_si128(dqm, data);
|
||||
reg = _mm_andnot_si128(dqm, reg);
|
||||
reg = _mm_or_si128(data, reg);
|
||||
#endif
|
||||
|
||||
_mm_store_si128((__m128i *)regp, reg);
|
||||
}
|
||||
|
||||
//
|
||||
// SSSE3+ accelerated loads for group II.
|
||||
//
|
||||
// TODO: Reverse-engineer what happens when loads to vector elements must
|
||||
// wraparound. Do we just discard the data, as below, or does the
|
||||
// data effectively get rotated around the edge of the vector?
|
||||
//
|
||||
// TODO: Reverse-engineer what happens when element != 0.
|
||||
//
|
||||
void rsp_vload_group2(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
|
||||
rsp_vect_t dqm)
|
||||
{
|
||||
unsigned offset = addr & 0x7;
|
||||
__m128i data, zero;
|
||||
|
||||
// Always load in 8-byte chunks to emulate wraparound.
|
||||
if (offset)
|
||||
{
|
||||
uint32_t aligned_addr_lo = addr & ~0x7;
|
||||
uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF;
|
||||
uint64_t datalow, datahigh;
|
||||
|
||||
memcpy(&datalow, rsp->dmem + aligned_addr_lo, sizeof(datalow));
|
||||
memcpy(&datahigh, rsp->dmem + aligned_addr_hi, sizeof(datahigh));
|
||||
|
||||
// TODO: Get rid of GNU extensions.
|
||||
datalow = __builtin_bswap64(datalow);
|
||||
datahigh = __builtin_bswap64(datahigh);
|
||||
datahigh >>= ((8 - offset) << 3);
|
||||
datalow <<= (offset << 3);
|
||||
datalow = datahigh | datalow;
|
||||
datalow = __builtin_bswap64(datalow);
|
||||
|
||||
data = _mm_loadl_epi64((__m128i *)&datalow);
|
||||
}
|
||||
|
||||
else
|
||||
data = _mm_loadl_epi64((__m128i *)(rsp->dmem + addr));
|
||||
|
||||
// "Unpack" the data.
|
||||
zero = _mm_setzero_si128();
|
||||
data = _mm_unpacklo_epi8(zero, data);
|
||||
|
||||
#if 0
|
||||
if (rsp->pipeline.exdf_latch.request.type != RSP_MEM_REQUEST_PACK)
|
||||
#endif
|
||||
data = _mm_srli_epi16(data, 1);
|
||||
|
||||
_mm_store_si128((__m128i *)regp, data);
|
||||
}
|
||||
|
||||
//
|
||||
// SSSE3+ accelerated loads for group IV. Byteswap big-endian to 2-byte
|
||||
// little-endian vector. Stop loading at quadword boundaries.
|
||||
//
|
||||
// TODO: Reverse-engineer what happens when loads from vector elements
|
||||
// must wraparound (i.e., the address offset is small, starting
|
||||
// element is large).
|
||||
//
|
||||
void rsp_vload_group4(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
|
||||
rsp_vect_t dqm)
|
||||
{
|
||||
uint32_t aligned_addr = addr & 0xFF0;
|
||||
unsigned offset = addr & 0xF;
|
||||
unsigned ror;
|
||||
|
||||
__m128i data = _mm_load_si128((__m128i *)(rsp->dmem + aligned_addr));
|
||||
|
||||
// TODO: Use of element is almost certainly wrong...
|
||||
ror = 16 - element + offset;
|
||||
|
||||
#if 0
|
||||
if (rsp->pipeline.exdf_latch.request.type != RSP_MEM_REQUEST_QUAD)
|
||||
#endif
|
||||
dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm);
|
||||
|
||||
#ifndef __SSSE3__
|
||||
data = sse2_pshufb(data, ror_b2l_keys[ror & 0xF]);
|
||||
dqm = sse2_pshufb(dqm, ror_b2l_keys[ror & 0xF]);
|
||||
#else
|
||||
__m128i dkey = _mm_load_si128((__m128i *)(ror_b2l_keys[ror & 0xF]));
|
||||
data = _mm_shuffle_epi8(data, dkey);
|
||||
dqm = _mm_shuffle_epi8(dqm, dkey);
|
||||
#endif
|
||||
|
||||
// Mask and mux in the data.
|
||||
#ifdef __SSE4_1__
|
||||
data = _mm_blendv_epi8(reg, data, dqm);
|
||||
#else
|
||||
data = _mm_and_si128(dqm, data);
|
||||
reg = _mm_andnot_si128(dqm, reg);
|
||||
data = _mm_or_si128(data, reg);
|
||||
#endif
|
||||
|
||||
_mm_store_si128((__m128i *)regp, data);
|
||||
}
|
||||
|
||||
//
|
||||
// SSE3+ accelerated stores for group I. Byteswap 2-byte little-endian
|
||||
// vector back to big-endian. Start at vector element offset, wrapping
|
||||
// around the edge of the vector as necessary.
|
||||
//
|
||||
// TODO: Reverse-engineer what happens when stores from vector elements
|
||||
// must wraparound. Do we just stop storing the data, or do we
|
||||
// continue storing from the front of the vector, as below?
|
||||
//
|
||||
void rsp_vstore_group1(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
|
||||
rsp_vect_t dqm)
|
||||
{
|
||||
unsigned offset = addr & 0x7;
|
||||
unsigned ror = element - offset;
|
||||
__m128i data;
|
||||
|
||||
// Shift the DQM up to the point where we mux in the data.
|
||||
#ifndef __SSSE3__
|
||||
dqm = sse2_pshufb(dqm, sll_l2b_keys[offset]);
|
||||
#else
|
||||
__m128i ekey = _mm_load_si128((__m128i *)(sll_l2b_keys[offset]));
|
||||
dqm = _mm_shuffle_epi8(dqm, ekey);
|
||||
#endif
|
||||
|
||||
// Rotate the reg to align with the DQM.
|
||||
#ifndef __SSSE3__
|
||||
reg = sse2_pshufb(reg, ror_l2b_keys[ror & 0xF]);
|
||||
#else
|
||||
ekey = _mm_load_si128((__m128i *)(ror_l2b_keys[ror & 0xF]));
|
||||
reg = _mm_shuffle_epi8(reg, ekey);
|
||||
#endif
|
||||
|
||||
// Always load in 8-byte chunks to emulate wraparound.
|
||||
if (offset)
|
||||
{
|
||||
uint32_t aligned_addr_lo = addr & ~0x7;
|
||||
uint32_t aligned_addr_hi = (aligned_addr_lo + 8) & 0xFFF;
|
||||
__m128i temp;
|
||||
|
||||
data = _mm_loadl_epi64((__m128i *)(rsp->dmem + aligned_addr_lo));
|
||||
temp = _mm_loadl_epi64((__m128i *)(rsp->dmem + aligned_addr_hi));
|
||||
data = _mm_unpacklo_epi64(data, temp);
|
||||
|
||||
// Mask and mux in the data.
|
||||
#ifdef __SSE4_1__
|
||||
data = _mm_blendv_epi8(data, reg, dqm);
|
||||
#else
|
||||
data = _mm_andnot_si128(dqm, data);
|
||||
reg = _mm_and_si128(dqm, reg);
|
||||
data = _mm_or_si128(data, reg);
|
||||
#endif
|
||||
|
||||
_mm_storel_epi64((__m128i *)(rsp->dmem + aligned_addr_lo), data);
|
||||
|
||||
data = _mm_srli_si128(data, 8);
|
||||
_mm_storel_epi64((__m128i *)(rsp->dmem + aligned_addr_hi), data);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
data = _mm_loadl_epi64((__m128i *)(rsp->dmem + addr));
|
||||
|
||||
// Mask and mux in the data.
|
||||
#ifdef __SSE4_1__
|
||||
data = _mm_blendv_epi8(data, reg, dqm);
|
||||
#else
|
||||
data = _mm_andnot_si128(dqm, data);
|
||||
reg = _mm_and_si128(dqm, reg);
|
||||
data = _mm_or_si128(data, reg);
|
||||
#endif
|
||||
|
||||
_mm_storel_epi64((__m128i *)(rsp->dmem + addr), data);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// SSE3+ accelerated stores for group II. Byteswap 2-byte little-endian
|
||||
// vector back to big-endian. Start at vector element offset, wrapping
|
||||
// around the edge of the vector as necessary.
|
||||
//
|
||||
// TODO: Reverse-engineer what happens when stores from vector elements
|
||||
// must wraparound. Do we just stop storing the data, or do we
|
||||
// continue storing from the front of the vector, as below?
|
||||
//
|
||||
// TODO: Reverse-engineer what happens when element != 0.
|
||||
//
|
||||
void rsp_vstore_group2(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
|
||||
rsp_vect_t dqm)
|
||||
{
|
||||
|
||||
// "Pack" the data.
|
||||
#if 0
|
||||
if (rsp->pipeline.exdf_latch.request.type != RSP_MEM_REQUEST_PACK)
|
||||
#endif
|
||||
reg = _mm_slli_epi16(reg, 1);
|
||||
|
||||
reg = _mm_srai_epi16(reg, 8);
|
||||
reg = _mm_packs_epi16(reg, reg);
|
||||
|
||||
// TODO: Always store in 8-byte chunks to emulate wraparound.
|
||||
_mm_storel_epi64((__m128i *)(rsp->dmem + addr), reg);
|
||||
}
|
||||
|
||||
//
|
||||
// SSE3+ accelerated stores for group IV. Byteswap 2-byte little-endian
|
||||
// vector back to big-endian. Stop storing at quadword boundaries.
|
||||
//
|
||||
void rsp_vstore_group4(RSP::CPUState *rsp, uint32_t addr, unsigned element, uint16_t *regp, rsp_vect_t reg,
|
||||
rsp_vect_t dqm)
|
||||
{
|
||||
uint32_t aligned_addr = addr & 0xFF0;
|
||||
unsigned offset = addr & 0xF;
|
||||
unsigned rol = offset;
|
||||
|
||||
__m128i data = _mm_load_si128((__m128i *)(rsp->dmem + aligned_addr));
|
||||
|
||||
#if 0
|
||||
if (rsp->pipeline.exdf_latch.request.type == RSP_MEM_REQUEST_QUAD)
|
||||
#else
|
||||
if (0)
|
||||
#endif
|
||||
rol -= element;
|
||||
|
||||
// TODO: How is this adjusted for SRV when e != 0?
|
||||
else dqm = _mm_cmpeq_epi8(_mm_setzero_si128(), dqm);
|
||||
|
||||
#ifndef __SSSE3__
|
||||
reg = sse2_pshufb(reg, rol_l2b_keys[rol & 0xF]);
|
||||
#else
|
||||
__m128i ekey = _mm_load_si128((__m128i *)(rol_l2b_keys[rol & 0xF]));
|
||||
reg = _mm_shuffle_epi8(reg, ekey);
|
||||
#endif
|
||||
|
||||
// Mask and mux out the data, write.
|
||||
#ifdef __SSE4_1__
|
||||
data = _mm_blendv_epi8(data, reg, dqm);
|
||||
#else
|
||||
reg = _mm_and_si128(dqm, reg);
|
||||
data = _mm_andnot_si128(dqm, data);
|
||||
data = _mm_or_si128(data, reg);
|
||||
#endif
|
||||
|
||||
_mm_store_si128((__m128i *)(rsp->dmem + aligned_addr), data);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef RSP_IMPL_H
|
||||
#define RSP_IMPL_H
|
||||
|
||||
#include "clamp.h"
|
||||
#include "vabs.h"
|
||||
#include "vadd.h"
|
||||
#include "vaddc.h"
|
||||
#include "vand.h"
|
||||
#include "vch.h"
|
||||
#include "vcl.h"
|
||||
#include "vcmp.h"
|
||||
#include "vcr.h"
|
||||
#include "vdivh.h"
|
||||
#include "vmac.h"
|
||||
#include "vmov.h"
|
||||
#include "vmrg.h"
|
||||
#include "vmul.h"
|
||||
#include "vmulh.h"
|
||||
#include "vmull.h"
|
||||
#include "vmulm.h"
|
||||
#include "vmuln.h"
|
||||
#include "vor.h"
|
||||
#include "vrcpsq.h"
|
||||
#include "vrsq.h"
|
||||
#include "vsub.h"
|
||||
#include "vsubc.h"
|
||||
#include "vxor.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vabs.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vabs(__m128i vs, __m128i vt, __m128i *acc_lo)
|
||||
{
|
||||
__m128i vs_zero = _mm_cmpeq_epi16(vs, _mm_setzero_si128());
|
||||
__m128i sign_lt = _mm_srai_epi16(vs, 15);
|
||||
__m128i vd = _mm_andnot_si128(vs_zero, vt);
|
||||
|
||||
// Careful: if VT = 0x8000 and VS is negative,
|
||||
// acc_lo will be 0x8000 but vd will be 0x7FFF.
|
||||
vd = _mm_xor_si128(vd, sign_lt);
|
||||
*acc_lo = _mm_sub_epi16(vd, sign_lt);
|
||||
return _mm_subs_epi16(vd, sign_lt);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vadd.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vadd(__m128i vs, __m128i vt, __m128i carry, __m128i *acc_lo)
|
||||
{
|
||||
__m128i vd, minimum, maximum;
|
||||
|
||||
// VCC uses unsaturated arithmetic.
|
||||
vd = _mm_add_epi16(vs, vt);
|
||||
*acc_lo = _mm_sub_epi16(vd, carry);
|
||||
|
||||
// VD is the signed sum of the two sources and the carry. Since we
|
||||
// have to saturate the sum of all three, we have to be clever.
|
||||
minimum = _mm_min_epi16(vs, vt);
|
||||
maximum = _mm_max_epi16(vs, vt);
|
||||
minimum = _mm_subs_epi16(minimum, carry);
|
||||
return _mm_adds_epi16(minimum, maximum);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vaddc.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vaddc(__m128i vs, __m128i vt, __m128i zero, __m128i *sn)
|
||||
{
|
||||
__m128i sat_sum, unsat_sum;
|
||||
|
||||
sat_sum = _mm_adds_epu16(vs, vt);
|
||||
unsat_sum = _mm_add_epi16(vs, vt);
|
||||
|
||||
*sn = _mm_cmpeq_epi16(sat_sum, unsat_sum);
|
||||
*sn = _mm_cmpeq_epi16(*sn, zero);
|
||||
|
||||
return unsat_sum;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vand.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vand(__m128i vs, __m128i vt)
|
||||
{
|
||||
return _mm_and_si128(vs, vt);
|
||||
}
|
||||
|
||||
static inline __m128i rsp_vnand(__m128i vs, __m128i vt)
|
||||
{
|
||||
__m128i vd = _mm_and_si128(vs, vt);
|
||||
return _mm_xor_si128(vd, _mm_set1_epi32(0xffffffffu));
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vch.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vch(__m128i vs, __m128i vt, __m128i zero, __m128i *ge, __m128i *le, __m128i *eq,
|
||||
__m128i *sign, __m128i *vce)
|
||||
{
|
||||
|
||||
__m128i sign_negvt, vt_neg;
|
||||
__m128i diff, diff_zero, diff_sel_mask;
|
||||
__m128i diff_gez, diff_lez;
|
||||
|
||||
// sign = (vs ^ vt) < 0
|
||||
*sign = _mm_xor_si128(vs, vt);
|
||||
*sign = _mm_cmplt_epi16(*sign, zero);
|
||||
|
||||
// sign_negvt = sign ? -vt : vt
|
||||
sign_negvt = _mm_xor_si128(vt, *sign);
|
||||
sign_negvt = _mm_sub_epi16(sign_negvt, *sign);
|
||||
|
||||
// Compute diff, diff_zero:
|
||||
diff = _mm_sub_epi16(vs, sign_negvt);
|
||||
diff_zero = _mm_cmpeq_epi16(diff, zero);
|
||||
|
||||
// Compute le/ge:
|
||||
vt_neg = _mm_cmplt_epi16(vt, zero);
|
||||
diff_lez = _mm_cmpgt_epi16(diff, zero);
|
||||
diff_gez = _mm_or_si128(diff_lez, diff_zero);
|
||||
diff_lez = _mm_cmpeq_epi16(zero, diff_lez);
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
*ge = _mm_blendv_epi8(diff_gez, vt_neg, *sign);
|
||||
*le = _mm_blendv_epi8(vt_neg, diff_lez, *sign);
|
||||
#else
|
||||
*ge = _mm_and_si128(*sign, vt_neg);
|
||||
diff_gez = _mm_andnot_si128(*sign, diff_gez);
|
||||
*ge = _mm_or_si128(*ge, diff_gez);
|
||||
|
||||
*le = _mm_and_si128(*sign, diff_lez);
|
||||
diff_lez = _mm_andnot_si128(*sign, vt_neg);
|
||||
*le = _mm_or_si128(*le, diff_lez);
|
||||
#endif
|
||||
|
||||
// Compute vce:
|
||||
*vce = _mm_cmpeq_epi16(diff, *sign);
|
||||
*vce = _mm_and_si128(*vce, *sign);
|
||||
|
||||
// Compute !eq:
|
||||
*eq = _mm_or_si128(diff_zero, *vce);
|
||||
*eq = _mm_cmpeq_epi16(*eq, zero);
|
||||
|
||||
// Compute result:
|
||||
#ifdef __SSE4_1__
|
||||
diff_sel_mask = _mm_blendv_epi8(*ge, *le, *sign);
|
||||
return _mm_blendv_epi8(vs, sign_negvt, diff_sel_mask);
|
||||
#else
|
||||
diff_lez = _mm_and_si128(*sign, *le);
|
||||
diff_gez = _mm_andnot_si128(*sign, *ge);
|
||||
diff_sel_mask = _mm_or_si128(diff_lez, diff_gez);
|
||||
|
||||
diff_lez = _mm_and_si128(diff_sel_mask, sign_negvt);
|
||||
diff_gez = _mm_andnot_si128(diff_sel_mask, vs);
|
||||
return _mm_or_si128(diff_lez, diff_gez);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vcl.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vcl(__m128i vs, __m128i vt, __m128i zero, __m128i *ge, __m128i *le, __m128i eq, __m128i sign,
|
||||
__m128i vce)
|
||||
{
|
||||
|
||||
__m128i sign_negvt, diff, ncarry, nvce, diff_zero;
|
||||
__m128i le_case1, le_case2, le_eq, do_le;
|
||||
__m128i ge_eq, do_ge, mux_mask;
|
||||
|
||||
// sign_negvt = sign ? -vt : vt
|
||||
sign_negvt = _mm_xor_si128(vt, sign);
|
||||
sign_negvt = _mm_sub_epi16(sign_negvt, sign);
|
||||
|
||||
// Compute diff, diff_zero, ncarry, and nvce:
|
||||
// Note: diff = sign ? (vs + vt) : (vs - vt).
|
||||
diff = _mm_sub_epi16(vs, sign_negvt);
|
||||
ncarry = _mm_adds_epu16(vs, vt);
|
||||
ncarry = _mm_cmpeq_epi16(diff, ncarry);
|
||||
nvce = _mm_cmpeq_epi16(vce, zero);
|
||||
diff_zero = _mm_cmpeq_epi16(diff, zero);
|
||||
|
||||
// Compute results for if (sign && ne):
|
||||
le_case1 = _mm_and_si128(diff_zero, ncarry);
|
||||
le_case1 = _mm_and_si128(nvce, le_case1);
|
||||
le_case2 = _mm_or_si128(diff_zero, ncarry);
|
||||
le_case2 = _mm_and_si128(vce, le_case2);
|
||||
le_eq = _mm_or_si128(le_case1, le_case2);
|
||||
|
||||
// Compute results for if (!sign && ne):
|
||||
ge_eq = _mm_subs_epu16(vt, vs);
|
||||
ge_eq = _mm_cmpeq_epi16(ge_eq, zero);
|
||||
|
||||
// Blend everything together. Caveat: we don't update
|
||||
// the results of ge/le if ne is false, so be careful.
|
||||
do_le = _mm_andnot_si128(eq, sign);
|
||||
#ifdef __SSE4_1__
|
||||
*le = _mm_blendv_epi8(*le, le_eq, do_le);
|
||||
#else
|
||||
le_eq = _mm_and_si128(do_le, le_eq);
|
||||
*le = _mm_andnot_si128(do_le, *le);
|
||||
*le = _mm_or_si128(le_eq, *le);
|
||||
#endif
|
||||
|
||||
do_ge = _mm_or_si128(sign, eq);
|
||||
#ifdef __SSE4_1__
|
||||
*ge = _mm_blendv_epi8(ge_eq, *ge, do_ge);
|
||||
#else
|
||||
*ge = _mm_and_si128(do_ge, *ge);
|
||||
ge_eq = _mm_andnot_si128(do_ge, ge_eq);
|
||||
*ge = _mm_or_si128(ge_eq, *ge);
|
||||
#endif
|
||||
|
||||
// Mux the result based on the value of sign.
|
||||
#ifdef __SSE4_1__
|
||||
mux_mask = _mm_blendv_epi8(*ge, *le, sign);
|
||||
#else
|
||||
do_le = _mm_and_si128(sign, *le);
|
||||
do_ge = _mm_andnot_si128(sign, *ge);
|
||||
mux_mask = _mm_or_si128(do_le, do_ge);
|
||||
#endif
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
return _mm_blendv_epi8(vs, sign_negvt, mux_mask);
|
||||
#else
|
||||
sign_negvt = _mm_and_si128(mux_mask, sign_negvt);
|
||||
vs = _mm_andnot_si128(mux_mask, vs);
|
||||
return _mm_or_si128(sign_negvt, vs);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vcmp.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_veq(__m128i vs, __m128i vt, __m128i zero, __m128i *le, __m128i eq, __m128i sign)
|
||||
{
|
||||
__m128i equal = _mm_cmpeq_epi16(vs, vt);
|
||||
|
||||
*le = _mm_andnot_si128(eq, equal);
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
return _mm_blendv_epi8(vt, vs, *le);
|
||||
#else
|
||||
vs = _mm_and_si128(*le, vs);
|
||||
vt = _mm_andnot_si128(*le, vt);
|
||||
return _mm_or_si128(vs, vt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i rsp_vge(__m128i vs, __m128i vt, __m128i zero, __m128i *le, __m128i eq, __m128i sign)
|
||||
{
|
||||
__m128i equal = _mm_cmpeq_epi16(vs, vt);
|
||||
|
||||
__m128i gt = _mm_cmpgt_epi16(vs, vt);
|
||||
__m128i equalsign = _mm_and_si128(eq, sign);
|
||||
|
||||
equal = _mm_andnot_si128(equalsign, equal);
|
||||
*le = _mm_or_si128(gt, equal);
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
return _mm_blendv_epi8(vt, vs, *le);
|
||||
#else
|
||||
vs = _mm_and_si128(*le, vs);
|
||||
vt = _mm_andnot_si128(*le, vt);
|
||||
return _mm_or_si128(vs, vt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i rsp_vlt(__m128i vs, __m128i vt, __m128i zero, __m128i *le, __m128i eq, __m128i sign)
|
||||
{
|
||||
__m128i equal = _mm_cmpeq_epi16(vs, vt);
|
||||
__m128i lt = _mm_cmplt_epi16(vs, vt);
|
||||
|
||||
equal = _mm_and_si128(eq, equal);
|
||||
equal = _mm_and_si128(sign, equal);
|
||||
*le = _mm_or_si128(lt, equal);
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
return _mm_blendv_epi8(vt, vs, *le);
|
||||
#else
|
||||
vs = _mm_and_si128(*le, vs);
|
||||
vt = _mm_andnot_si128(*le, vt);
|
||||
return _mm_or_si128(vs, vt);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline __m128i rsp_vne(__m128i vs, __m128i vt, __m128i zero, __m128i *le, __m128i eq, __m128i sign)
|
||||
{
|
||||
__m128i equal = _mm_cmpeq_epi16(vs, vt);
|
||||
__m128i nequal = _mm_cmpeq_epi16(equal, zero);
|
||||
|
||||
*le = _mm_and_si128(eq, equal);
|
||||
*le = _mm_or_si128(*le, nequal);
|
||||
|
||||
#ifdef INTENSE_DEBUG
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "VS[%d] = %d\n", i, reinterpret_cast<int16_t *>(&vs)[i]);
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "VT[%d] = %d\n", i, reinterpret_cast<int16_t *>(&vt)[i]);
|
||||
#endif
|
||||
|
||||
#ifdef __SSE4_1__
|
||||
return _mm_blendv_epi8(vt, vs, *le);
|
||||
#else
|
||||
vs = _mm_and_si128(*le, vs);
|
||||
vt = _mm_andnot_si128(*le, vt);
|
||||
return _mm_or_si128(vs, vt);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vcr.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vcr(__m128i vs, __m128i vt, __m128i zero, __m128i *ge, __m128i *le)
|
||||
{
|
||||
__m128i diff_sel_mask, diff_gez, diff_lez;
|
||||
__m128i sign, sign_notvt;
|
||||
|
||||
#ifdef INTENSE_DEBUG
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "VS[%d] = %d\n", i, reinterpret_cast<int16_t *>(&vs)[i]);
|
||||
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "VT[%d] = %d\n", i, reinterpret_cast<int16_t *>(&vt)[i]);
|
||||
#endif
|
||||
|
||||
// sign = (vs ^ vt) < 0
|
||||
sign = _mm_xor_si128(vs, vt);
|
||||
sign = _mm_srai_epi16(sign, 15);
|
||||
|
||||
// Compute le
|
||||
diff_lez = _mm_and_si128(vs, sign);
|
||||
diff_lez = _mm_add_epi16(diff_lez, vt);
|
||||
*le = _mm_srai_epi16(diff_lez, 15);
|
||||
|
||||
// Compute ge
|
||||
diff_gez = _mm_or_si128(vs, sign);
|
||||
diff_gez = _mm_min_epi16(diff_gez, vt);
|
||||
*ge = _mm_cmpeq_epi16(diff_gez, vt);
|
||||
|
||||
// sign_notvt = sn ? ~vt : vt
|
||||
sign_notvt = _mm_xor_si128(vt, sign);
|
||||
|
||||
// Compute result:
|
||||
#ifdef __SSE4_1__
|
||||
diff_sel_mask = _mm_blendv_epi8(*ge, *le, sign);
|
||||
return _mm_blendv_epi8(vs, sign_notvt, diff_sel_mask);
|
||||
#else
|
||||
diff_sel_mask = _mm_sub_epi16(*le, *ge);
|
||||
diff_sel_mask = _mm_and_si128(diff_sel_mask, sign);
|
||||
diff_sel_mask = _mm_add_epi16(diff_sel_mask, *ge);
|
||||
|
||||
zero = _mm_sub_epi16(sign_notvt, vs);
|
||||
zero = _mm_and_si128(zero, diff_sel_mask);
|
||||
return _mm_add_epi16(zero, vs);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vrcp.c
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
inline __m128i rsp_vdivh(RSP::CPUState *rsp, unsigned src, unsigned e, unsigned dest, unsigned de)
|
||||
{
|
||||
|
||||
// Get the element from VT.
|
||||
rsp->cp2.div_in = rsp->cp2.regs[src].e[e & 0x7];
|
||||
|
||||
// Write out the upper part of the result.
|
||||
rsp->cp2.regs[dest].e[de & 0x7] = rsp->cp2.div_out;
|
||||
return rsp_vect_load_unshuffled_operand(rsp->cp2.regs[dest].e);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmacf.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
template <bool VMACU>
|
||||
static inline __m128i rsp_vmacf_vmacu(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
|
||||
__m128i *acc_hi)
|
||||
{
|
||||
__m128i overflow_hi_mask, overflow_md_mask;
|
||||
__m128i lo, md, hi, carry, overflow_mask;
|
||||
|
||||
// Get the product and shift it over
|
||||
// being sure to save the carries.
|
||||
lo = _mm_mullo_epi16(vs, vt);
|
||||
hi = _mm_mulhi_epi16(vs, vt);
|
||||
|
||||
md = _mm_slli_epi16(hi, 1);
|
||||
carry = _mm_srli_epi16(lo, 15);
|
||||
hi = _mm_srai_epi16(hi, 15);
|
||||
md = _mm_or_si128(md, carry);
|
||||
lo = _mm_slli_epi16(lo, 1);
|
||||
|
||||
// Tricky part: start accumulating everything.
|
||||
// Get/keep the carry as we'll add it in later.
|
||||
overflow_mask = _mm_adds_epu16(*acc_lo, lo);
|
||||
*acc_lo = _mm_add_epi16(*acc_lo, lo);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
|
||||
// Add in the carry. If the middle portion is
|
||||
// already 0xFFFF and we have a carry, we have
|
||||
// to carry the all the way up to hi.
|
||||
md = _mm_sub_epi16(md, overflow_mask);
|
||||
carry = _mm_cmpeq_epi16(md, zero);
|
||||
carry = _mm_and_si128(carry, overflow_mask);
|
||||
hi = _mm_sub_epi16(hi, carry);
|
||||
|
||||
// Accumulate the middle portion.
|
||||
overflow_mask = _mm_adds_epu16(*acc_md, md);
|
||||
*acc_md = _mm_add_epi16(*acc_md, md);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
|
||||
// Finish up the accumulation of the... accumulator.
|
||||
*acc_hi = _mm_add_epi16(*acc_hi, hi);
|
||||
*acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask);
|
||||
|
||||
// VMACU
|
||||
if (VMACU)
|
||||
{
|
||||
overflow_hi_mask = _mm_srai_epi16(*acc_hi, 15);
|
||||
overflow_md_mask = _mm_srai_epi16(*acc_md, 15);
|
||||
md = _mm_or_si128(overflow_md_mask, *acc_md);
|
||||
overflow_mask = _mm_cmpgt_epi16(*acc_hi, zero);
|
||||
md = _mm_andnot_si128(overflow_hi_mask, md);
|
||||
return _mm_or_si128(overflow_mask, md);
|
||||
}
|
||||
|
||||
// VMACF
|
||||
else
|
||||
return rsp_sclamp_acc_tomd(*acc_md, *acc_hi);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmov.c
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
inline __m128i rsp_vmov(RSP::CPUState *rsp, unsigned src, unsigned e, unsigned dest, unsigned de)
|
||||
{
|
||||
uint16_t data;
|
||||
|
||||
// Get the element from VT.
|
||||
data = rsp->cp2.regs[src].e[e & 0x7];
|
||||
|
||||
// Write out the upper part of the result.
|
||||
rsp->cp2.regs[dest].e[de & 0x7] = data;
|
||||
return rsp_vect_load_unshuffled_operand(rsp->cp2.regs[dest].e);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmrg.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vmrg(__m128i vs, __m128i vt, __m128i le)
|
||||
{
|
||||
#ifdef __SSE4_1__
|
||||
return _mm_blendv_epi8(vt, vs, le);
|
||||
#else
|
||||
vs = _mm_and_si128(le, vs);
|
||||
vt = _mm_andnot_si128(le, vt);
|
||||
return _mm_or_si128(vs, vt);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmudh.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vmudh(__m128i vs, __m128i vt, __m128i *acc_md, __m128i *acc_hi)
|
||||
{
|
||||
*acc_md = _mm_mullo_epi16(vs, vt);
|
||||
*acc_hi = _mm_mulhi_epi16(vs, vt);
|
||||
|
||||
return rsp_sclamp_acc_tomd(*acc_md, *acc_hi);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmul.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
//
|
||||
// TODO: CHECK ME.
|
||||
//
|
||||
|
||||
template <bool VMULU>
|
||||
static inline __m128i rsp_vmulf_vmulu(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
|
||||
__m128i *acc_hi)
|
||||
{
|
||||
__m128i lo, hi, round, sign1, sign2, eq, neq, neg;
|
||||
|
||||
lo = _mm_mullo_epi16(vs, vt);
|
||||
round = _mm_cmpeq_epi16(zero, zero);
|
||||
sign1 = _mm_srli_epi16(lo, 15);
|
||||
lo = _mm_add_epi16(lo, lo);
|
||||
round = _mm_slli_epi16(round, 15);
|
||||
hi = _mm_mulhi_epi16(vs, vt);
|
||||
sign2 = _mm_srli_epi16(lo, 15);
|
||||
*acc_lo = _mm_add_epi16(round, lo);
|
||||
sign1 = _mm_add_epi16(sign1, sign2);
|
||||
|
||||
hi = _mm_slli_epi16(hi, 1);
|
||||
neq = eq = _mm_cmpeq_epi16(vs, vt);
|
||||
*acc_md = _mm_add_epi16(hi, sign1);
|
||||
|
||||
neg = _mm_srai_epi16(*acc_md, 15);
|
||||
|
||||
// VMULU
|
||||
if (VMULU)
|
||||
{
|
||||
*acc_hi = _mm_andnot_si128(eq, neg);
|
||||
hi = _mm_or_si128(*acc_md, neg);
|
||||
return _mm_andnot_si128(*acc_hi, hi);
|
||||
}
|
||||
|
||||
// VMULF
|
||||
else
|
||||
{
|
||||
eq = _mm_and_si128(eq, neg);
|
||||
*acc_hi = _mm_andnot_si128(neq, neg);
|
||||
return _mm_add_epi16(*acc_md, eq);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmulh.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
template <bool VMADH>
|
||||
static inline __m128i rsp_vmadh_vmudh(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
|
||||
__m128i *acc_hi)
|
||||
{
|
||||
__m128i lo, hi, overflow_mask;
|
||||
|
||||
lo = _mm_mullo_epi16(vs, vt);
|
||||
hi = _mm_mulhi_epi16(vs, vt);
|
||||
|
||||
// VMADH
|
||||
if (VMADH)
|
||||
{
|
||||
// Tricky part: start accumulate everything.
|
||||
// Get/keep the carry as we'll add it in later.
|
||||
overflow_mask = _mm_adds_epu16(*acc_md, lo);
|
||||
*acc_md = _mm_add_epi16(*acc_md, lo);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
|
||||
hi = _mm_sub_epi16(hi, overflow_mask);
|
||||
*acc_hi = _mm_add_epi16(*acc_hi, hi);
|
||||
}
|
||||
|
||||
// VMUDH
|
||||
else
|
||||
{
|
||||
*acc_lo = zero;
|
||||
*acc_md = lo;
|
||||
*acc_hi = hi;
|
||||
}
|
||||
|
||||
return rsp_sclamp_acc_tomd(*acc_md, *acc_hi);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmadl.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
template <bool VMADL>
|
||||
static inline __m128i rsp_vmadl_vmudl(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
|
||||
__m128i *acc_hi)
|
||||
{
|
||||
__m128i hi, overflow_mask;
|
||||
|
||||
hi = _mm_mulhi_epu16(vs, vt);
|
||||
|
||||
// VMADL
|
||||
if (VMADL)
|
||||
{
|
||||
|
||||
// Tricky part: start accumulate everything.
|
||||
// Get/keep the carry as we'll add it in later.
|
||||
overflow_mask = _mm_adds_epu16(*acc_lo, hi);
|
||||
*acc_lo = _mm_add_epi16(*acc_lo, hi);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
hi = _mm_sub_epi16(zero, overflow_mask);
|
||||
|
||||
// Check for overflow of the upper sum.
|
||||
//
|
||||
// TODO: Since hi can only be {0,1}, we should
|
||||
// be able to generalize this for performance.
|
||||
overflow_mask = _mm_adds_epu16(*acc_md, hi);
|
||||
*acc_md = _mm_add_epi16(*acc_md, hi);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
|
||||
// Finish up the accumulation of the... accumulator.
|
||||
// Since the product was unsigned, only worry about
|
||||
// positive overflow (i.e.: borrowing not possible).
|
||||
*acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask);
|
||||
|
||||
return rsp_uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero);
|
||||
}
|
||||
|
||||
// VMUDL
|
||||
else
|
||||
{
|
||||
*acc_lo = hi;
|
||||
*acc_md = zero;
|
||||
*acc_hi = zero;
|
||||
|
||||
return hi;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmulm.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
template <bool VMADM>
|
||||
static inline __m128i rsp_vmadm_vmudm(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
|
||||
__m128i *acc_hi)
|
||||
{
|
||||
__m128i lo, hi, sign, overflow_mask;
|
||||
|
||||
lo = _mm_mullo_epi16(vs, vt);
|
||||
hi = _mm_mulhi_epu16(vs, vt);
|
||||
|
||||
// What we're really want to do is unsigned vs * signed vt.
|
||||
// However, we have no such instructions to do so.
|
||||
//
|
||||
// There's a trick to "fix" an unsigned product, though:
|
||||
// If vt was negative, take the upper 16-bits of the product
|
||||
// and subtract vs.
|
||||
sign = _mm_srai_epi16(vs, 15);
|
||||
vt = _mm_and_si128(vt, sign);
|
||||
hi = _mm_sub_epi16(hi, vt);
|
||||
|
||||
// VMADM
|
||||
if (VMADM)
|
||||
{
|
||||
// Tricky part: start accumulate everything.
|
||||
// Get/keep the carry as we'll add it in later.
|
||||
overflow_mask = _mm_adds_epu16(*acc_lo, lo);
|
||||
*acc_lo = _mm_add_epi16(*acc_lo, lo);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
|
||||
// This is REALLY clever. Since the product results from
|
||||
// two 16-bit components, one positive and one negative,
|
||||
// we don't have to worry about carrying the 1 (we can
|
||||
// only borrow) past 32-bits. So we can just add it here.
|
||||
hi = _mm_sub_epi16(hi, overflow_mask);
|
||||
|
||||
// Check for overflow of the upper sum.
|
||||
overflow_mask = _mm_adds_epu16(*acc_md, hi);
|
||||
*acc_md = _mm_add_epi16(*acc_md, hi);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
|
||||
// Finish up the accumulation of the... accumulator.
|
||||
*acc_hi = _mm_add_epi16(*acc_hi, _mm_srai_epi16(hi, 15));
|
||||
*acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask);
|
||||
|
||||
return rsp_sclamp_acc_tomd(*acc_md, *acc_hi);
|
||||
}
|
||||
|
||||
// VMUDM
|
||||
else
|
||||
{
|
||||
*acc_lo = lo;
|
||||
*acc_md = hi;
|
||||
*acc_hi = _mm_srai_epi16(hi, 15);
|
||||
|
||||
return hi;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vmuln.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
template <bool VMADN>
|
||||
static inline __m128i rsp_vmadn_vmudn(__m128i vs, __m128i vt, __m128i zero, __m128i *acc_lo, __m128i *acc_md,
|
||||
__m128i *acc_hi)
|
||||
{
|
||||
__m128i lo, hi, sign, overflow_mask;
|
||||
|
||||
#ifdef INTENSE_DEBUG
|
||||
if (VMADN)
|
||||
{
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "ACC LO[%u] = %d\n", i, reinterpret_cast<int16_t *>(acc_lo)[i]);
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "ACC MD[%u] = %d\n", i, reinterpret_cast<int16_t *>(acc_md)[i]);
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "ACC HI[%u] = %d\n", i, reinterpret_cast<int16_t *>(acc_hi)[i]);
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "VS[%u] = %d\n", i, reinterpret_cast<int16_t *>(&vs)[i]);
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "VT[%u] = %d\n", i, reinterpret_cast<int16_t *>(&vt)[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
lo = _mm_mullo_epi16(vs, vt);
|
||||
hi = _mm_mulhi_epu16(vs, vt);
|
||||
|
||||
// What we're really want to do is unsigned vs * signed vt.
|
||||
// However, we have no such instructions to do so.
|
||||
//
|
||||
// There's a trick to "fix" an unsigned product, though:
|
||||
// If vt was negative, take the upper 16-bits of the product
|
||||
// and subtract vs.
|
||||
sign = _mm_srai_epi16(vt, 15);
|
||||
vs = _mm_and_si128(vs, sign);
|
||||
hi = _mm_sub_epi16(hi, vs);
|
||||
|
||||
// VMADN
|
||||
if (VMADN)
|
||||
{
|
||||
// Tricky part: start accumulate everything.
|
||||
// Get/keep the carry as we'll add it in later.
|
||||
overflow_mask = _mm_adds_epu16(*acc_lo, lo);
|
||||
*acc_lo = _mm_add_epi16(*acc_lo, lo);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_lo, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
|
||||
// This is REALLY clever. Since the product results from
|
||||
// two 16-bit components, one positive and one negative,
|
||||
// we don't have to worry about carrying the 1 (we can
|
||||
// only borrow) past 32-bits. So we can just add it here.
|
||||
hi = _mm_sub_epi16(hi, overflow_mask);
|
||||
|
||||
// Check for overflow of the upper sum.
|
||||
overflow_mask = _mm_adds_epu16(*acc_md, hi);
|
||||
*acc_md = _mm_add_epi16(*acc_md, hi);
|
||||
|
||||
overflow_mask = _mm_cmpeq_epi16(*acc_md, overflow_mask);
|
||||
overflow_mask = _mm_cmpeq_epi16(overflow_mask, zero);
|
||||
|
||||
// Finish up the accumulation of the... accumulator.
|
||||
*acc_hi = _mm_add_epi16(*acc_hi, _mm_srai_epi16(hi, 15));
|
||||
*acc_hi = _mm_sub_epi16(*acc_hi, overflow_mask);
|
||||
#ifdef INTENSE_DEBUG
|
||||
auto ret = rsp_uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero);
|
||||
for (unsigned i = 0; i < 8; i++)
|
||||
fprintf(stderr, "VD[%u] = %d\n", i, reinterpret_cast<int16_t *>(&ret)[i]);
|
||||
return ret;
|
||||
#else
|
||||
return rsp_uclamp_acc(*acc_lo, *acc_md, *acc_hi, zero);
|
||||
#endif
|
||||
}
|
||||
|
||||
// VMUDN
|
||||
else
|
||||
{
|
||||
*acc_lo = lo;
|
||||
*acc_md = hi;
|
||||
*acc_hi = _mm_srai_epi16(hi, 15);
|
||||
|
||||
return lo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vor.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vor(__m128i vs, __m128i vt)
|
||||
{
|
||||
return _mm_or_si128(vs, vt);
|
||||
}
|
||||
|
||||
static inline __m128i rsp_vnor(__m128i vs, __m128i vt)
|
||||
{
|
||||
__m128i vd = _mm_or_si128(vs, vt);
|
||||
return _mm_xor_si128(vd, _mm_set1_epi32(0xffffffffu));
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vrcpsq.c
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
#include "../../../rsp/reciprocal.h"
|
||||
|
||||
template <bool VRSQ>
|
||||
inline __m128i rsp_vrcp_vrsq(RSP::CPUState *rsp, int dp, unsigned src, unsigned e, unsigned dest, unsigned de)
|
||||
{
|
||||
uint32_t dp_input, sp_input;
|
||||
int32_t input, result;
|
||||
|
||||
int16_t vt;
|
||||
|
||||
int32_t input_mask, data;
|
||||
unsigned shift, idx;
|
||||
|
||||
// Get the element from VT.
|
||||
vt = rsp->cp2.regs[src].e[e & 0x7];
|
||||
|
||||
dp_input = ((uint32_t)rsp->cp2.div_in << 16) | (uint16_t)vt;
|
||||
sp_input = vt;
|
||||
|
||||
input = (dp) ? dp_input : sp_input;
|
||||
input_mask = input >> 31;
|
||||
data = input ^ input_mask;
|
||||
|
||||
if (input > -32768)
|
||||
data -= input_mask;
|
||||
|
||||
// Handle edge cases.
|
||||
if (data == 0)
|
||||
result = 0x7fffFFFFU;
|
||||
|
||||
else if (input == -32768)
|
||||
result = 0xffff0000U;
|
||||
|
||||
// Main case: compute the reciprocal.
|
||||
else
|
||||
{
|
||||
|
||||
// TODO: Clean this up.
|
||||
#ifdef _MSC_VER
|
||||
unsigned long bsf_index;
|
||||
_BitScanReverse(&bsf_index, data);
|
||||
shift = 31 - bsf_index;
|
||||
#else
|
||||
shift = __builtin_clz(data);
|
||||
#endif
|
||||
|
||||
// VRSQ
|
||||
if (VRSQ)
|
||||
{
|
||||
idx = (((unsigned long long)data << shift) & 0x7FC00000U) >> 22;
|
||||
idx = ((idx | 0x200) & 0x3FE) | (shift % 2);
|
||||
result = rsp_reciprocal_rom[idx];
|
||||
|
||||
result = ((0x10000 | result) << 14) >> ((31 - shift) >> 1);
|
||||
}
|
||||
|
||||
// VRCP
|
||||
else
|
||||
{
|
||||
idx = (((unsigned long long)data << shift) & 0x7FC00000U) >> 22;
|
||||
result = rsp_reciprocal_rom[idx];
|
||||
|
||||
result = ((0x10000 | result) << 14) >> (31 - shift);
|
||||
}
|
||||
|
||||
result = result ^ input_mask;
|
||||
}
|
||||
|
||||
// Write out the results.
|
||||
rsp->cp2.div_out = result >> 16;
|
||||
rsp->cp2.regs[dest].e[de & 0x7] = result;
|
||||
|
||||
return rsp_vect_load_unshuffled_operand(rsp->cp2.regs[dest].e);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vrsq.c
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
#include "../../../rsp/reciprocal.h"
|
||||
#include <string.h>
|
||||
|
||||
// Mask table for vrsq(LH) functions.
|
||||
alignas(16) static const uint16_t vrsq_mask_table[8][8] = {
|
||||
{ 0xffff, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0xffff, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0xffff, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0xffff, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0xffff, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0xffff, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0xffff, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0xffff }
|
||||
};
|
||||
|
||||
inline __m128i rsp_vrsq(RSP::CPUState *rsp, int dp, unsigned src, unsigned e, unsigned dest, unsigned de)
|
||||
{
|
||||
uint32_t dp_input, sp_input;
|
||||
int32_t input, result;
|
||||
int16_t vt;
|
||||
|
||||
int32_t input_mask, data;
|
||||
unsigned shift, idx;
|
||||
|
||||
// Get the element from VT.
|
||||
vt = rsp->cp2.regs[src].e[e & 0x7];
|
||||
|
||||
dp_input = ((uint32_t)rsp->cp2.div_in << 16) | (uint16_t)vt;
|
||||
sp_input = vt;
|
||||
|
||||
input = (dp) ? dp_input : sp_input;
|
||||
input_mask = input >> 31;
|
||||
data = input ^ input_mask;
|
||||
|
||||
if (input > -32768)
|
||||
data -= input_mask;
|
||||
|
||||
// Handle edge cases.
|
||||
if (data == 0)
|
||||
result = 0x7fffFFFFU;
|
||||
|
||||
else if (input == -32768)
|
||||
result = 0xffff0000U;
|
||||
|
||||
// Main case: compute the reciprocal.
|
||||
else
|
||||
{
|
||||
|
||||
//TODO: Clean this up.
|
||||
#ifdef _MSC_VER
|
||||
unsigned long bsf_index;
|
||||
_BitScanReverse(&bsf_index, data);
|
||||
shift = 31 - bsf_index;
|
||||
#else
|
||||
shift = __builtin_clz(data);
|
||||
#endif
|
||||
|
||||
idx = (((unsigned long long)data << shift) & 0x7FC00000U) >> 22;
|
||||
idx = ((idx | 0x200) & 0x3FE) | (shift % 2);
|
||||
result = rsp_reciprocal_rom[idx];
|
||||
|
||||
result = ((0x10000 | result) << 14) >> ((31 - shift) >> 1);
|
||||
result = result ^ input_mask;
|
||||
}
|
||||
|
||||
// Write out the results.
|
||||
rsp->cp2.div_out = result >> 16;
|
||||
rsp->cp2.regs[dest].e[de & 0x7] = result;
|
||||
|
||||
return rsp_vect_load_unshuffled_operand(rsp->cp2.regs[dest].e);
|
||||
}
|
||||
|
||||
inline __m128i rsp_vrsqh(RSP::CPUState *rsp, unsigned src, unsigned e, unsigned dest, unsigned de)
|
||||
{
|
||||
__m128i vd, vd_mask, b_result;
|
||||
|
||||
int16_t elements[8];
|
||||
|
||||
// Get the element from VT.
|
||||
memcpy(elements, rsp->cp2.regs + src, sizeof(elements));
|
||||
rsp->cp2.div_in = elements[e];
|
||||
|
||||
// Write out the upper part of the result.
|
||||
vd_mask = _mm_load_si128((__m128i *)vrsq_mask_table[de]);
|
||||
vd = _mm_load_si128((__m128i *)(rsp->cp2.regs + dest));
|
||||
vd = _mm_andnot_si128(vd_mask, vd);
|
||||
|
||||
b_result = _mm_set1_epi16(rsp->cp2.div_out);
|
||||
b_result = _mm_and_si128(vd_mask, b_result);
|
||||
return _mm_or_si128(b_result, vd);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vsub.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vsub(__m128i vs, __m128i vt, __m128i carry, __m128i *acc_lo)
|
||||
{
|
||||
__m128i unsat_diff, sat_diff, overflow, vd;
|
||||
|
||||
// acc_lo uses saturated arithmetic.
|
||||
unsat_diff = _mm_sub_epi16(vt, carry);
|
||||
sat_diff = _mm_subs_epi16(vt, carry);
|
||||
|
||||
*acc_lo = _mm_sub_epi16(vs, unsat_diff);
|
||||
vd = _mm_subs_epi16(vs, sat_diff);
|
||||
|
||||
// VD is the signed diff of the two sources and the carry. Since we
|
||||
// have to saturate the diff of all three, we have to be clever.
|
||||
overflow = _mm_cmpgt_epi16(sat_diff, unsat_diff);
|
||||
return _mm_adds_epi16(vd, overflow);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vsubc.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vsubc(__m128i vs, __m128i vt, __m128i zero, __m128i *eq, __m128i *sn)
|
||||
{
|
||||
__m128i equal, sat_udiff, sat_udiff_zero;
|
||||
|
||||
sat_udiff = _mm_subs_epu16(vs, vt);
|
||||
equal = _mm_cmpeq_epi16(vs, vt);
|
||||
sat_udiff_zero = _mm_cmpeq_epi16(sat_udiff, zero);
|
||||
|
||||
*eq = _mm_cmpeq_epi16(equal, zero);
|
||||
*sn = _mm_andnot_si128(equal, sat_udiff_zero);
|
||||
|
||||
return _mm_sub_epi16(vs, vt);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// arch/x86_64/rsp/vxor.h
|
||||
//
|
||||
// This file is subject to the terms and conditions defined in
|
||||
// 'LICENSE', which is part of this source code package.
|
||||
//
|
||||
|
||||
static inline __m128i rsp_vxor(__m128i vs, __m128i vt)
|
||||
{
|
||||
return _mm_xor_si128(vs, vt);
|
||||
}
|
||||
|
||||
static inline __m128i rsp_vnxor(__m128i vs, __m128i vt)
|
||||
{
|
||||
__m128i vd = _mm_xor_si128(vs, vt);
|
||||
return _mm_xor_si128(vd, _mm_set1_epi32(0xffffffffu));
|
||||
}
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z $ANDROID_HOME ]; then
|
||||
echo "Please define ANDROID_HOME environment variable to where Android SDK is installed, usually ~/Android/Sdk."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p build-android-aarch64
|
||||
cd build-android-aarch64
|
||||
cmake .. -DCMAKE_TOOLCHAIN_FILE="$ANDROID_HOME/ndk-bundle/build/cmake/android.toolchain.cmake" \
|
||||
-DANDROID_ABI=arm64-v8a \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DANDROID_PLATFORM=android-26 \
|
||||
-DPARALLEL_RSP_DEBUG_JIT=OFF
|
||||
cmake --build . --parallel
|
||||
cd ..
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p build-native
|
||||
cd build-native
|
||||
cmake .. -DCMAKE_BUILD_TYPE=Release -DPARALLEL_RSP_DEBUG_JIT=OFF
|
||||
cmake --build . --parallel
|
||||
cd ..
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
./build_android_aarch64.sh || exit 1
|
||||
cd build-android-aarch64
|
||||
echo "Running Android test suite ..."
|
||||
ctest --no-label-summary --verbose >android-aarch64.log || exit 1
|
||||
cd ..
|
||||
|
||||
./build_native.sh || exit 1
|
||||
cd build-native
|
||||
echo "Running native test suite ..."
|
||||
ctest --no-label-summary --verbose >native.log || exit 1
|
||||
cd ..
|
||||
|
||||
echo "Comparing output ..."
|
||||
echo "=============================="
|
||||
diff -Naur build-native/native.log build-android-aarch64/android-aarch64.log
|
||||
echo "=============================="
|
||||
@@ -0,0 +1,5 @@
|
||||
#ifndef RSP_CPU_STATE_HPP
|
||||
#define RSP_CPU_STATE_HPP
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
RSP_TEST = main
|
||||
|
||||
PROGRAM = $(RSP_TEST)
|
||||
MIPS_OBJ = $(RSP_TEST).o
|
||||
|
||||
include Makefile.mips
|
||||
@@ -0,0 +1,40 @@
|
||||
####
|
||||
## Basic Makefile for RSP-MIPS
|
||||
##
|
||||
######
|
||||
|
||||
TARGET_ELF = $(PROGRAM).elf
|
||||
TARGET_BIN = $(PROGRAM).bin
|
||||
TARGET_GLOBAL_BIN = $(PROGRAM).global.bin
|
||||
MIPS_LD_SCRIPT = rsp-mips.ld
|
||||
|
||||
MIPS_OBJCOPY = mipsel-linux-gnu-objcopy
|
||||
MIPS_CC = mipsel-linux-gnu-gcc
|
||||
MIPS_AS = mipsel-linux-gnu-as
|
||||
MIPS_LD = mipsel-linux-gnu-ld
|
||||
CRT_OBJ = start.o rsp-mips.o
|
||||
|
||||
all: $(TARGET_BIN) $(TARGET_GLOBAL_BIN)
|
||||
|
||||
crt-obj: $(CRT_OBJ)
|
||||
|
||||
$(TARGET_BIN): $(TARGET_ELF)
|
||||
$(MIPS_OBJCOPY) -j .text $< $(TARGET_BIN) -O binary
|
||||
|
||||
$(TARGET_GLOBAL_BIN): $(TARGET_ELF)
|
||||
$(MIPS_OBJCOPY) -j .data $< $(TARGET_GLOBAL_BIN) -O binary
|
||||
|
||||
$(TARGET_ELF): $(MIPS_OBJ) $(CRT_OBJ)
|
||||
$(MIPS_LD) -T $(MIPS_LD_SCRIPT) -o $@ $(CRT_OBJ) $(MIPS_OBJ) -EB
|
||||
|
||||
%.o: %.s
|
||||
$(MIPS_AS) -o $@ $< -EB -mabi=eabi -march=mips1
|
||||
|
||||
%.o: %.c rsp-mips.h
|
||||
$(MIPS_CC) -c -o $@ $< -Os -EB -march=mips1 -mabi=eabi -mno-abicalls -std=gnu99 -nostdlib
|
||||
|
||||
clean:
|
||||
rm -f $(MIPS_OBJ) $(CRT_OBJ) $(TARGET_ELF) $(TARGET_HEX) $(TARGET_GLOBAL_HEX) $(TARGET_BIN) $(TARGET_GLOBAL_BIN)
|
||||
|
||||
.PHONY: all clean tools
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 40
|
||||
li $t1, -20
|
||||
add $t2, $t0, $t1
|
||||
addu $t3, $t0, $t1
|
||||
|
||||
li $t0, -5
|
||||
li $t1, -4
|
||||
add $t2, $t0, $t1
|
||||
addu $t3, $t0, $t1
|
||||
break
|
||||
@@ -0,0 +1,9 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $a0, 17
|
||||
addi $t0, $a0, -8
|
||||
addi $t1, $a0, 8
|
||||
addiu $t2, $a0, -8
|
||||
addiu $t3, $a0, 8
|
||||
break
|
||||
@@ -0,0 +1,7 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 17
|
||||
li $t1, 5
|
||||
and $t2, $t0, $t1
|
||||
break
|
||||
@@ -0,0 +1,6 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $a0, -1
|
||||
andi $t0, $a0, 50000
|
||||
break
|
||||
@@ -0,0 +1,20 @@
|
||||
# This works on the Lightning JIT, but hangs the reference.
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
li $t1, 1
|
||||
li $t2, 2
|
||||
li $t3, 0
|
||||
beq $t0, $t1, taken0 # This will be taken.
|
||||
beq $t0, $t1, taken1 # This will also be taken.
|
||||
li $t3, 3 # This will not be executed.
|
||||
|
||||
taken0:
|
||||
li $t6, 5 # This will be executed, the second branch then kicks in and runs taken1 path.
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4 # This will be executed.
|
||||
break
|
||||
@@ -0,0 +1,18 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
li $t1, 1
|
||||
li $t2, 2
|
||||
li $t3, 0
|
||||
beq $t0, $t1, taken0 # This will be taken.
|
||||
beq $t0, $t2, taken1 # Will not be taken.
|
||||
li $t3, 3
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,18 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
li $t1, 1
|
||||
li $t2, 2
|
||||
li $t3, 0
|
||||
beq $t0, $t2, taken0 # This will not be taken, should be ignored.
|
||||
beq $t0, $t1, taken1 # This will be taken.
|
||||
li $t3, 3
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, -1
|
||||
bgez $t0, taken1 # This will not be taken.
|
||||
li $t2, 10
|
||||
|
||||
li $t0, 0
|
||||
bgez $t0, taken1 # This will be taken.
|
||||
li $t2, 20
|
||||
|
||||
li $t0, 1
|
||||
bgez $t0, taken1 # This will be taken.
|
||||
li $t2, 30
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, -1
|
||||
bgezal $t0, taken1 # This will not be taken.
|
||||
li $t2, 10
|
||||
|
||||
li $t0, 0
|
||||
bgezal $t0, taken1 # This will be taken.
|
||||
li $t2, 20
|
||||
|
||||
li $t0, 1
|
||||
bgezal $t0, taken1 # This will be taken.
|
||||
li $t2, 30
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, -1
|
||||
bgtz $t0, taken1 # This will not be taken.
|
||||
li $t2, 10
|
||||
|
||||
li $t0, 0
|
||||
bgtz $t0, taken1 # This will not be taken.
|
||||
li $t2, 20
|
||||
|
||||
li $t0, 1
|
||||
bgtz $t0, taken1 # This will be taken.
|
||||
li $t2, 30
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
blez $t0, taken1 # This will not be taken.
|
||||
li $t2, 10
|
||||
|
||||
li $t0, 0
|
||||
blez $t0, taken1 # This will be taken.
|
||||
li $t2, 20
|
||||
|
||||
li $t0, 0
|
||||
blez $t0, taken1 # This will be taken.
|
||||
li $t2, 30
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
bltz $t0, taken1 # This will not be taken.
|
||||
li $t2, 10
|
||||
|
||||
li $t0, 0
|
||||
bltz $t0, taken1 # This will not be taken.
|
||||
li $t2, 20
|
||||
|
||||
li $t0, -1
|
||||
bltz $t0, taken1 # This will be taken.
|
||||
li $t2, 30
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
bltzal $t0, taken1 # This will not be taken.
|
||||
li $t2, 10
|
||||
|
||||
li $t0, 0
|
||||
bltzal $t0, taken1 # This will not be taken.
|
||||
li $t2, 20
|
||||
|
||||
li $t0, -1
|
||||
bltzal $t0, taken1 # This will be taken.
|
||||
li $t2, 30
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,20 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
li $t1, 1
|
||||
li $t2, 2
|
||||
li $t3, 0
|
||||
bne $t0, $t1, taken0 # This will not be taken.
|
||||
nop
|
||||
|
||||
bne $t0, $t2, taken1 # Will be taken.
|
||||
li $t3, 3
|
||||
|
||||
taken0:
|
||||
li $t4, 5
|
||||
break
|
||||
taken1:
|
||||
li $t4, 4
|
||||
break
|
||||
@@ -0,0 +1,15 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t1, ((0x50000000) << 5) & 0xffffffff
|
||||
li $t0, 0x50000000
|
||||
sll $t0, $t0, 5
|
||||
bne $t0, $t1, error
|
||||
nop
|
||||
|
||||
li $t2, 1
|
||||
break
|
||||
|
||||
error:
|
||||
li $t2, 2
|
||||
break
|
||||
@@ -0,0 +1,14 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 100
|
||||
mtc0 $t0, $1
|
||||
bgez $t0, bar
|
||||
mfc0 $t1, $1
|
||||
li $t1, 200 # Should not execute.
|
||||
break
|
||||
|
||||
bar:
|
||||
li $t2, 400
|
||||
break
|
||||
@@ -0,0 +1,16 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 10
|
||||
li $t2, 10
|
||||
nop
|
||||
.word (0x12 << 26) | (4 << 21) | (2 << 11) | (8 << 16) | (4 << 7)
|
||||
.word (0x12 << 26) | (0 << 21) | (2 << 11) | (9 << 16) | (4 << 7)
|
||||
#mtc2 $t0, $2, 4
|
||||
#mfc2 $t1, $2, 4
|
||||
|
||||
ctc2 $t2, $2
|
||||
cfc2 $t3, $2
|
||||
|
||||
break
|
||||
@@ -0,0 +1,15 @@
|
||||
.data
|
||||
buffer:
|
||||
.hword 10, 20, 30, 40, 50, 60, 70, 80
|
||||
.hword 20, 30, 40, 50, 60, 70, 80, 90
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
la $t0, buffer
|
||||
# lqv 2, 0, 1(t0)
|
||||
.word (0x32 << 26) | (4 << 11) | (2 << 16) | (0 << 7) | (1 << 0) | (8 << 21)
|
||||
# sqv 2, 0, 2(t0)
|
||||
.word (0x3a << 26) | (4 << 11) | (2 << 16) | (0 << 7) | (2 << 0) | (8 << 21)
|
||||
break
|
||||
@@ -0,0 +1,18 @@
|
||||
.data
|
||||
buffer:
|
||||
.hword 10, 20, 30, 40, 50, 60, 70, 80
|
||||
.hword 20, 30, 40, 50, 60, 70, 80, 90
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
la $t0, buffer
|
||||
# lqv 2, 0, 0(t0)
|
||||
.word (0x32 << 26) | (4 << 11) | (2 << 16) | (0 << 7) | (0 << 0) | (8 << 21)
|
||||
# lqv 3, 0, 1(t0)
|
||||
.word (0x32 << 26) | (4 << 11) | (3 << 16) | (0 << 7) | (1 << 0) | (8 << 21)
|
||||
|
||||
.word (0x25 << 25) | (4 << 6) | (2 << 11) | (3 << 16) | (17 << 0) | (0 << 21)
|
||||
# vsub v4, v2, v3, 0
|
||||
break
|
||||
@@ -0,0 +1,15 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
blez $t0, foo
|
||||
break
|
||||
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
foo:
|
||||
break
|
||||
@@ -0,0 +1,21 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
.align 10
|
||||
main:
|
||||
li $t0, 1
|
||||
.rept 126
|
||||
nop
|
||||
.endr
|
||||
bgtz $t0, foobar
|
||||
# New block begins here,
|
||||
j foobar2
|
||||
li $t2, 2 # This should not execute
|
||||
|
||||
foobar:
|
||||
li $t3, 3 # This should execute, then we move to foobar2
|
||||
break
|
||||
|
||||
foobar2:
|
||||
li $t4, 4 # This executes.
|
||||
break
|
||||
@@ -0,0 +1,19 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
.align 10
|
||||
main:
|
||||
li $t0, 0
|
||||
.rept 126
|
||||
nop
|
||||
.endr
|
||||
bgtz $t0, foobar
|
||||
# New block begins here,
|
||||
# last instruction will be bgtz which needs to promote its delay slot
|
||||
# into a new block.
|
||||
# First instruction of any block have to handle potential latent delay slots like these.
|
||||
li $t1, 1
|
||||
li $t2, 2 # This should execute
|
||||
|
||||
foobar:
|
||||
break
|
||||
@@ -0,0 +1,19 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
.align 10
|
||||
main:
|
||||
li $t0, 1
|
||||
.rept 126
|
||||
nop
|
||||
.endr
|
||||
bgtz $t0, foobar
|
||||
# New block begins here,
|
||||
# last instruction will be bgtz which needs to promote its delay slot
|
||||
# into a new block.
|
||||
# First instruction of any block have to handle potential latent delay slots like these.
|
||||
li $t1, 1
|
||||
li $t2, 2 # This should not execute
|
||||
|
||||
foobar:
|
||||
break
|
||||
@@ -0,0 +1,20 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
j indelay
|
||||
nop
|
||||
|
||||
j die # Test to make sure this becomes a conditional branch.
|
||||
|
||||
indelay:
|
||||
j notdie
|
||||
li $t0, 1
|
||||
|
||||
die:
|
||||
li $t0, 0x10000
|
||||
|
||||
notdie:
|
||||
li $t1, 2
|
||||
break
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
bgtz $0, dummy
|
||||
jal callsite
|
||||
li $t5, 10
|
||||
|
||||
jr $s5
|
||||
callsite:
|
||||
lw $t2, 184($0)
|
||||
li $t1, 10
|
||||
break
|
||||
|
||||
dummy:
|
||||
nop
|
||||
break
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
jal indelay
|
||||
nop
|
||||
|
||||
jal die # Test to make sure this becomes a conditional branch.
|
||||
|
||||
indelay:
|
||||
jal notdie
|
||||
move $t2, $ra
|
||||
li $t0, 1
|
||||
|
||||
die:
|
||||
li $t0, 0x10000
|
||||
|
||||
notdie:
|
||||
li $t1, 2
|
||||
break
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
la $t5, notdie
|
||||
la $ra, indelay
|
||||
jalr $a0, $ra
|
||||
move $ra, $a0
|
||||
|
||||
j die # Test to make sure this becomes a conditional branch.
|
||||
|
||||
indelay:
|
||||
jalr $a0, $t5
|
||||
move $t0, $a0
|
||||
|
||||
die:
|
||||
li $t0, 0x10000
|
||||
|
||||
notdie:
|
||||
li $t1, 2
|
||||
break
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
la $t5, notdie
|
||||
la $ra, indelay
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
j die # Test to make sure this becomes a conditional branch.
|
||||
|
||||
indelay:
|
||||
jr $t5
|
||||
li $t0, 1
|
||||
|
||||
die:
|
||||
li $t0, 0x10000
|
||||
|
||||
notdie:
|
||||
li $t1, 2
|
||||
break
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
.data
|
||||
.byte 0, 0, 0
|
||||
foobar:
|
||||
.byte 0x72, 0x91
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
la $t1, foobar
|
||||
lb $t0, 1($t1)
|
||||
break
|
||||
@@ -0,0 +1,11 @@
|
||||
.data
|
||||
.byte 0, 0, 0
|
||||
foobar:
|
||||
.byte 0x72, 0x91
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
la $t1, foobar
|
||||
lbu $t0, 1($t1)
|
||||
break
|
||||
@@ -0,0 +1,12 @@
|
||||
.data
|
||||
.byte 0, 0, 0, 0
|
||||
foobar:
|
||||
.byte 0
|
||||
.byte 0x92, 0x70
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
la $t1, foobar
|
||||
lh $t0, 1($t1)
|
||||
break
|
||||
@@ -0,0 +1,11 @@
|
||||
.data
|
||||
.byte 0, 0, 0, 0
|
||||
foobar:
|
||||
.byte 0x92, 0x70
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
la $t1, foobar
|
||||
lh $t0, 0($t1)
|
||||
break
|
||||
@@ -0,0 +1,12 @@
|
||||
.data
|
||||
.byte 0, 0, 0, 0
|
||||
foobar:
|
||||
.byte 0
|
||||
.byte 0x92, 0x70
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
la $t1, foobar
|
||||
lhu $t0, 1($t1)
|
||||
break
|
||||
@@ -0,0 +1,11 @@
|
||||
.data
|
||||
.byte 0, 0, 0, 0
|
||||
foobar:
|
||||
.byte 0x92, 0x70
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
la $t1, foobar
|
||||
lhu $t0, 0($t1)
|
||||
break
|
||||
@@ -0,0 +1,5 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
lui $t0, 50000
|
||||
break
|
||||
@@ -0,0 +1,20 @@
|
||||
.data
|
||||
foo:
|
||||
.byte 0
|
||||
.byte 0xaa, 0xbb, 0xcc, 0xdd
|
||||
|
||||
.text
|
||||
.set noreorder
|
||||
.global main
|
||||
main:
|
||||
li $t0, 1
|
||||
la $t1, foo
|
||||
bgtz $t0, taken1
|
||||
lw $t1, 1($t1)
|
||||
|
||||
taken0:
|
||||
li $t5, 100
|
||||
break
|
||||
|
||||
taken1:
|
||||
break
|
||||
@@ -0,0 +1,15 @@
|
||||
.data
|
||||
.byte 0, 0, 0, 0
|
||||
foobar:
|
||||
.word 12345678
|
||||
.word 30
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
la $t1, foobar
|
||||
lw $t0, 0($t1)
|
||||
lw $t1, 1($t1)
|
||||
lw $t2, 2($t1)
|
||||
lw $t3, 3($t1)
|
||||
break
|
||||
@@ -0,0 +1,12 @@
|
||||
.data
|
||||
.byte 0, 0, 0, 0
|
||||
foobar:
|
||||
.word 12345678
|
||||
.word 30
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
la $t1, foobar
|
||||
lw $t0, 4($t1)
|
||||
break
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "rsp-mips.h"
|
||||
|
||||
u8 data[4] = { 0x10, 0x20, 0x30, 0x40 };
|
||||
|
||||
__attribute__((noinline))
|
||||
int load_byte(int i)
|
||||
{
|
||||
return data[i];
|
||||
}
|
||||
|
||||
int count = 3;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int res = 0;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
res += load_byte(i);
|
||||
}
|
||||
rsp_debug_break(res, res, res, res);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 17
|
||||
li $t1, 5
|
||||
nor $t2, $t0, $t1
|
||||
break
|
||||
@@ -0,0 +1,7 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 8
|
||||
li $t1, 50
|
||||
or $t2, $t0, $t1
|
||||
break
|
||||
@@ -0,0 +1,6 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $a0, 500
|
||||
ori $t0, $a0, 50000
|
||||
break
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef __RSP_MIPS_H
|
||||
#define __RSP_MIPS_H
|
||||
|
||||
typedef signed char s8;
|
||||
typedef unsigned char u8;
|
||||
typedef signed short s16;
|
||||
typedef unsigned short u16;
|
||||
typedef signed int s32;
|
||||
typedef unsigned int u32;
|
||||
typedef signed long long s64;
|
||||
typedef unsigned long long u64;
|
||||
typedef u32 size_t;
|
||||
|
||||
void rsp_break(void);
|
||||
void rsp_debug_break(u32 a, u32 b, u32 c, u32 d);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
SECTIONS {
|
||||
ENTRY(rsp_mips_start)
|
||||
. = 0x00400000;
|
||||
.text : { start.o (.text); * (.text*); }
|
||||
|
||||
. = 0x00700000;
|
||||
.data : { * (.data); * (.rodata*); * (.sbss); * (.scommon); }
|
||||
.bss : { * (.bss); }
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
.text
|
||||
.section .text
|
||||
|
||||
.global rsp_break
|
||||
.ent rsp_break
|
||||
.type rsp_break, @function
|
||||
rsp_break:
|
||||
break
|
||||
jr $ra
|
||||
.end rsp_break
|
||||
.size rsp_break, .-rsp_break
|
||||
|
||||
.global rsp_debug_break
|
||||
.ent rsp_debug_break
|
||||
.type rsp_debug_break, @function
|
||||
rsp_debug_break:
|
||||
break
|
||||
jr $ra
|
||||
.end rsp_debug_break
|
||||
.size rsp_debug_break, .-rsp_debug_break
|
||||
@@ -0,0 +1,21 @@
|
||||
.data
|
||||
foobar:
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 0xaabbccdd
|
||||
la $t1, foobar
|
||||
sb $t0, 0($t1)
|
||||
sb $t0, 1($t1)
|
||||
sb $t0, 3($t1)
|
||||
break
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
.data
|
||||
foobar:
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 0xaabbccdd
|
||||
la $t1, foobar
|
||||
sh $t0, 0($t1)
|
||||
sh $t0, 3($t1)
|
||||
break
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
.data
|
||||
foobar:
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
.word 0
|
||||
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 0xaabbccdd
|
||||
la $t1, foobar
|
||||
sh $t0, 0($t1)
|
||||
sh $t0, 2($t1)
|
||||
sh $t0, 6($t1)
|
||||
break
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 40
|
||||
sll $t0, $t0, 20
|
||||
break
|
||||
@@ -0,0 +1,7 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, 40
|
||||
li $t1, 20
|
||||
sllv $t0, $t0, $t1
|
||||
break
|
||||
@@ -0,0 +1,12 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $a0, 17
|
||||
li $a1, 5
|
||||
li $a2, -17
|
||||
li $a3, -5
|
||||
slt $t0, $a0, $a1
|
||||
slt $t1, $a3, $a0
|
||||
slt $t2, $a2, $a3
|
||||
slt $t3, $a2, $a1
|
||||
break
|
||||
@@ -0,0 +1,10 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $a0, 100000
|
||||
li $a1, -100000
|
||||
slti $t0, $a0, -40
|
||||
slti $t1, $a0, 40
|
||||
slti $t2, $a1, -40
|
||||
slti $t3, $a1, 40
|
||||
break
|
||||
@@ -0,0 +1,10 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $a0, 100000
|
||||
li $a1, -100000
|
||||
sltiu $t0, $a0, -40
|
||||
sltiu $t1, $a0, 40
|
||||
sltiu $t2, $a1, -40
|
||||
sltiu $t3, $a1, 40
|
||||
break
|
||||
@@ -0,0 +1,12 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $a0, 17
|
||||
li $a1, 5
|
||||
li $a2, -17
|
||||
li $a3, -5
|
||||
sltu $t0, $a0, $a1
|
||||
sltu $t1, $a3, $a0
|
||||
sltu $t2, $a2, $a3
|
||||
sltu $t3, $a2, $a1
|
||||
break
|
||||
@@ -0,0 +1,6 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, -15254
|
||||
sra $t0, $t0, 20
|
||||
break
|
||||
@@ -0,0 +1,7 @@
|
||||
.text
|
||||
.global main
|
||||
main:
|
||||
li $t0, -15254
|
||||
li $t1, 20
|
||||
srav $t0, $t0, $t1
|
||||
break
|
||||
Loaded 100 of 377 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user