--- /dev/null
+repo: f788ddc2d4711f6ac1125c99e9e4c5ebd3827ea7
+node: c44d274a4c4ab80d4b88353c045a78273ee76915
+branch: default
+latesttag: 2.0.0
+latesttagdistance: 1
--- /dev/null
+syntax: regexp
+
+^projects/unix/_obj/
+^projects/unix/mupen64plus-rsp-z64.so$
--- /dev/null
+0990ff8d7dcc61cd88e049c91eeaedb0bfbe70d7 1.99.4
+04507d8b67d1817deacdf4f0ca05a6b16af02f10 1.99.5
+3f5658dd8b57d4f1414a7ab858986c2589253590 2.0.0
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
--- /dev/null
+#/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+# * mupen64plus-rsp-z64 - Makefile *
+# * http://bitbucket.org/wahrhaft/mupen64plus-rsp-z64/ *
+# * Copyright (C) 2010 Jon Ring *
+# * Copyright (C) 2008-2009 Richard Goedeken *
+# * Copyright (C) 2007-2008 DarkJeztr Tillin9 *
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of the GNU General Public License as published by *
+# * the Free Software Foundation; either version 2 of the License, or *
+# * (at your option) any later version. *
+# * *
+# * This program is distributed in the hope that it will be useful, *
+# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+# * GNU General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU General Public License *
+# * along with this program; if not, write to the *
+# * Free Software Foundation, Inc., *
+# * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+# * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+# Makefile for Z64 RSP plugin in Mupen64plus.
+
+# detect operating system
+UNAME ?= $(shell uname -s)
+OS := NONE
+ifeq ("$(UNAME)","Linux")
+ OS = LINUX
+ SO_EXTENSION = so
+ SHARED = -shared
+endif
+ifeq ("$(UNAME)","linux")
+ OS = LINUX
+ SO_EXTENSION = so
+ SHARED = -shared
+endif
+ifneq ("$(filter GNU hurd,$(UNAME))","")
+ OS = LINUX
+ SO_EXTENSION = so
+ SHARED = -shared
+endif
+ifeq ("$(UNAME)","Darwin")
+ OS = OSX
+ SO_EXTENSION = dylib
+ SHARED = -bundle
+endif
+ifeq ("$(UNAME)","FreeBSD")
+ OS = FREEBSD
+ SO_EXTENSION = so
+ SHARED = -shared
+endif
+ifeq ("$(UNAME)","OpenBSD")
+ OS = FREEBSD
+ SO_EXTENSION = so
+ SHARED = -shared
+ $(warning OS type "$(UNAME)" not officially supported.')
+endif
+ifneq ("$(filter GNU/kFreeBSD kfreebsd,$(UNAME))","")
+ OS = LINUX
+ SO_EXTENSION = so
+ SHARED = -shared
+endif
+ifeq ("$(patsubst MINGW%,MINGW,$(UNAME))","MINGW")
+ OS = MINGW
+ SO_EXTENSION = dll
+ SHARED = -shared
+ PIC = 0
+endif
+ifeq ("$(OS)","NONE")
+ $(error OS type "$(UNAME)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues')
+endif
+
+# detect system architecture
+HOST_CPU ?= $(shell uname -m)
+NO_ASM ?= 1
+CPU := NONE
+ifneq ("$(filter x86_64 amd64,$(HOST_CPU))","")
+ CPU := X86
+ ifeq ("$(BITS)", "32")
+ ARCH_DETECTED := 64BITS_32
+ PIC ?= 0
+ else
+ ARCH_DETECTED := 64BITS
+ PIC ?= 1
+ endif
+endif
+ifneq ("$(filter pentium i%86,$(HOST_CPU))","")
+ CPU := X86
+ ARCH_DETECTED := 32BITS
+ PIC ?= 0
+endif
+ifneq ("$(filter ppc macppc socppc powerpc,$(HOST_CPU))","")
+ CPU := PPC
+ ARCH_DETECTED := 32BITS
+ BIG_ENDIAN := 1
+ PIC ?= 1
+ $(warning Architecture "$(HOST_CPU)" not officially supported.')
+endif
+ifneq ("$(filter ppc64 powerpc64,$(HOST_CPU))","")
+ CPU := PPC
+ ARCH_DETECTED := 64BITS
+ BIG_ENDIAN := 1
+ PIC ?= 1
+ $(warning Architecture "$(HOST_CPU)" not officially supported.')
+endif
+ifneq ("$(filter arm%,$(HOST_CPU))","")
+ ifeq ("$(filter arm%b,$(HOST_CPU))","")
+ CPU := ARM
+ ARCH_DETECTED := 32BITS
+ PIC ?= 1
+ HLEVIDEO ?= 1
+ CFLAGS += -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -mtune=cortex-a8 -fsigned-char
+ $(warning Architecture "$(HOST_CPU)" not officially supported.')
+ endif
+endif
+ifeq ("$(CPU)","NONE")
+ $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'http://code.google.com/p/mupen64plus/issues')
+endif
+
+# base CFLAGS, LDLIBS, and LDFLAGS
+OPTFLAGS ?= -O3 -flto
+WARNFLAGS ?= -Wall
+CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I../../src
+CXXFLAGS += -fvisibility-inlines-hidden
+LDFLAGS += $(SHARED)
+
+# Since we are building a shared library, we must compile with -fPIC on some architectures
+# On 32-bit x86 systems we do not want to use -fPIC because we don't have to and it has a big performance penalty on this arch
+ifeq ($(PIC), 1)
+ CFLAGS += -fPIC
+else
+ CFLAGS += -fno-PIC
+endif
+
+ifeq ($(HLEVIDEO), 1)
+ CFLAGS += -DVIDEO_HLE_ALLOWED
+ POSTFIX = -hlevideo
+endif
+
+ifeq ($(BIG_ENDIAN), 1)
+ CFLAGS += -DM64P_BIG_ENDIAN
+endif
+
+# tweak flags for 32-bit build on 64-bit system
+ifeq ($(ARCH_DETECTED), 64BITS_32)
+ ifeq ($(OS), FREEBSD)
+ $(error Do not use the BITS=32 option with FreeBSD, use -m32 and -m elf_i386)
+ endif
+ CFLAGS += -m32
+ LDFLAGS += -Wl,-m,elf_i386
+endif
+
+# set special flags per-system
+ifeq ($(OS), LINUX)
+ # only export api symbols
+ LDFLAGS += -Wl,-version-script,$(SRCDIR)/rsp_api_export.ver
+ LDLIBS += -ldl
+endif
+ifeq ($(OS), FREEBSD)
+ LDLIBS += -lc
+endif
+ifeq ($(OS), OSX)
+ # Select the proper SDK
+ # Also, SDKs are stored in a different location since XCode 4.3
+ OSX_SDK ?= $(shell sw_vers -productVersion | cut -f1 -f2 -d .)
+ OSX_XCODEMAJ = $(shell xcodebuild -version | grep '[0-9]*\.[0-9]*' | cut -f2 -d ' ' | cut -f1 -d .)
+ OSX_XCODEMIN = $(shell xcodebuild -version | grep '[0-9]*\.[0-9]*' | cut -f2 -d ' ' | cut -f2 -d .)
+ OSX_XCODEGE43 = $(shell echo "`expr $(OSX_XCODEMAJ) \>= 4``expr $(OSX_XCODEMIN) \>= 3`")
+ ifeq ($(OSX_XCODEGE43), 11)
+ OSX_SYSROOT := /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs
+ else
+ OSX_SYSROOT := /Developer/SDKs
+ endif
+
+ ifeq ($(CPU), X86)
+ ifeq ($(ARCH_DETECTED), 64BITS)
+ CFLAGS += -pipe -arch x86_64 -mmacosx-version-min=$(OSX_SDK) -isysroot $(OSX_SYSROOT)/MacOSX$(OSX_SDK).sdk
+ LDLIBS += -ldl
+ else
+ CFLAGS += -pipe -mmmx -msse -fomit-frame-pointer -arch i686 -mmacosx-version-min=$(OSX_SDK) -isysroot $(OSX_SYSROOT)/MacOSX$(OSX_SDK).sdk
+ LDLIBS += -ldl
+ endif
+ endif
+endif
+
+# set mupen64plus core API header path
+ifneq ("$(APIDIR)","")
+ CFLAGS += "-I$(APIDIR)"
+else
+ TRYDIR = ../../../mupen64plus-core/src/api
+ ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","")
+ CFLAGS += -I$(TRYDIR)
+ else
+ TRYDIR = /usr/local/include/mupen64plus
+ ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","")
+ CFLAGS += -I$(TRYDIR)
+ else
+ TRYDIR = /usr/include/mupen64plus
+ ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","")
+ CFLAGS += -I$(TRYDIR)
+ else
+ $(error Mupen64Plus API header files not found! Use makefile parameter APIDIR to force a location.)
+ endif
+ endif
+ endif
+endif
+
+# reduced compile output when running make without V=1
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+ Q_CC = @echo ' CC '$@;
+ Q_CXX = @echo ' CXX '$@;
+ Q_LD = @echo ' LD '$@;
+endif
+endif
+
+# set base program pointers and flags
+CC = $(CROSS_COMPILE)gcc
+CXX = $(CROSS_COMPILE)g++
+RM ?= rm -f
+INSTALL ?= install
+MKDIR ?= mkdir -p
+COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
+COMPILE.cc = $(Q_CXX)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
+LINK.o = $(Q_LD)$(CXX) $(CXXFLAGS) $(LDFLAGS) $(TARGET_ARCH)
+
+# set special flags for given Makefile parameters
+ifeq ($(DEBUG),1)
+ CFLAGS += -g
+ INSTALL_STRIP_FLAG ?=
+else
+ INSTALL_STRIP_FLAG ?= -s
+endif
+
+# set installation options
+ifeq ($(PREFIX),)
+ PREFIX := /usr/local
+endif
+ifeq ($(LIBDIR),)
+ LIBDIR := $(PREFIX)/lib
+endif
+ifeq ($(PLUGINDIR),)
+ PLUGINDIR := $(LIBDIR)/mupen64plus
+endif
+
+SRCDIR = ../../src
+OBJDIR = _obj$(POSTFIX)
+
+# list of source files to compile
+SOURCE = \
+ $(SRCDIR)/rsp.cpp \
+ $(SRCDIR)/rsp_opinfo.cpp \
+ $(SRCDIR)/rsp_recomp.cpp \
+ $(SRCDIR)/rsp_dasm.cpp \
+ $(SRCDIR)/main_rsp.cpp
+
+# generate a list of object files build, make a temporary directory for them
+OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter %.c, $(SOURCE)))
+OBJECTS += $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(filter %.cpp, $(SOURCE)))
+OBJDIRS = $(dir $(OBJECTS))
+$(shell $(MKDIR) $(OBJDIRS))
+
+# build targets
+TARGET = mupen64plus-rsp-z64$(POSTFIX).$(SO_EXTENSION)
+
+targets:
+ @echo "Mupen64Plus-rsp-z64 makefile. "
+ @echo " Targets:"
+ @echo " all == Build Mupen64Plus rsp-hle plugin"
+ @echo " clean == remove object files"
+ @echo " rebuild == clean and re-build all"
+ @echo " install == Install Mupen64Plus rsp-hle plugin"
+ @echo " uninstall == Uninstall Mupen64Plus rsp-hle plugin"
+ @echo " Options:"
+ @echo " BITS=32 == build 32-bit binaries on 64-bit machine"
+ @echo " APIDIR=path == path to find Mupen64Plus Core headers"
+ @echo " OPTFLAGS=flag == compiler optimization (default: -O3 -flto)"
+ @echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)"
+ @echo " PIC=(1|0) == Force enable/disable of position independent code"
+ @echo " HLEVIDEO=(1|0) == Move task of gfx emulation to a HLE video plugins"
+ @echo " POSTFIX=name == String added to the name of the the build (default: '')"
+ @echo " Install Options:"
+ @echo " PREFIX=path == install/uninstall prefix (default: /usr/local)"
+ @echo " LIBDIR=path == library prefix (default: PREFIX/lib)"
+ @echo " PLUGINDIR=path == path to install plugin libraries (default: LIBDIR/mupen64plus)"
+ @echo " DESTDIR=path == path to prepend to all installation paths (only for packagers)"
+ @echo " Debugging Options:"
+ @echo " DEBUG=1 == add debugging symbols"
+ @echo " V=1 == show verbose compiler output"
+
+all: $(TARGET)
+
+install: $(TARGET)
+ $(INSTALL) -d "$(DESTDIR)$(PLUGINDIR)"
+ $(INSTALL) -m 0644 $(INSTALL_STRIP_FLAG) $(TARGET) "$(DESTDIR)$(PLUGINDIR)"
+
+uninstall:
+ $(RM) "$(DESTDIR)$(PLUGINDIR)/$(TARGET)"
+
+clean:
+ $(RM) -r $(OBJDIR) $(TARGET)
+
+rebuild: clean all
+
+# build dependency files
+CFLAGS += -MD
+-include $(OBJECTS:.o=.d)
+
+CXXFLAGS += $(CFLAGS)
+
+# standard build rules
+$(OBJDIR)/%.o: $(SRCDIR)/%.c
+ $(COMPILE.c) -o $@ $<
+
+$(OBJDIR)/%.o: $(SRCDIR)/%.cpp
+ $(COMPILE.cc) -o $@ $<
+
+$(TARGET): $(OBJECTS)
+ $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
+
+.PHONY: all clean install uninstall targets
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#include "rsp.h"
+#include <assert.h>
+#include <stdarg.h>
+
+#define RSP_Z64_VERSION 0x020000
+#define RSP_PLUGIN_API_VERSION 0x020000
+
+static void (*l_DebugCallback)(void *, int, const char *) = NULL;
+static void *l_DebugCallContext = NULL;
+static bool l_PluginInit = false;
+
+#if 0
+static void dump()
+{
+ FILE * fp = fopen("rsp.dump", "w");
+ assert(fp);
+ fwrite(rdram, 8*1024, 1024, fp);
+ fwrite(rsp_dmem, 0x2000, 1, fp);
+ fwrite(rsp.ext.MI_INTR_REG, 4, 1, fp);
+
+ fwrite(rsp.ext.SP_MEM_ADDR_REG, 4, 1, fp);
+ fwrite(rsp.ext.SP_DRAM_ADDR_REG, 4, 1, fp);
+ fwrite(rsp.ext.SP_RD_LEN_REG, 4, 1, fp);
+ fwrite(rsp.ext.SP_WR_LEN_REG, 4, 1, fp);
+ fwrite(rsp.ext.SP_STATUS_REG, 4, 1, fp);
+ fwrite(rsp.ext.SP_DMA_FULL_REG, 4, 1, fp);
+ fwrite(rsp.ext.SP_DMA_BUSY_REG, 4, 1, fp);
+ fwrite(rsp.ext.SP_PC_REG, 4, 1, fp);
+ fwrite(rsp.ext.SP_SEMAPHORE_REG, 4, 1, fp);
+
+ fwrite(rsp.ext.DPC_START_REG, 4, 1, fp);
+ fwrite(rsp.ext.DPC_END_REG, 4, 1, fp);
+ fwrite(rsp.ext.DPC_CURRENT_REG, 4, 1, fp);
+ fwrite(rsp.ext.DPC_STATUS_REG, 4, 1, fp);
+ fwrite(rsp.ext.DPC_CLOCK_REG, 4, 1, fp);
+ fwrite(rsp.ext.DPC_BUFBUSY_REG, 4, 1, fp);
+ fwrite(rsp.ext.DPC_PIPEBUSY_REG, 4, 1, fp);
+ fwrite(rsp.ext.DPC_TMEM_REG, 4, 1, fp);
+ fclose(fp);
+}
+#endif
+
+void log(m64p_msg_level level, const char *msg, ...)
+{
+ char buf[1024];
+ va_list args;
+ va_start(args, msg);
+ vsnprintf(buf, 1023, msg, args);
+ buf[1023]='\0';
+ va_end(args);
+ if (l_DebugCallback)
+ {
+ l_DebugCallback(l_DebugCallContext, level, buf);
+ }
+}
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* DLL-exported functions */
+ EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context,
+ void (*DebugCallback)(void *, int, const char *))
+ {
+
+ if (l_PluginInit)
+ return M64ERR_ALREADY_INIT;
+
+ ///* first thing is to set the callback function for debug info */
+ l_DebugCallback = DebugCallback;
+ l_DebugCallContext = Context;
+
+ ///* this plugin doesn't use any Core library functions (ex for Configuration), so no need to keep the CoreLibHandle */
+
+ l_PluginInit = true;
+ return M64ERR_SUCCESS;
+ }
+
+ EXPORT m64p_error CALL PluginShutdown(void)
+ {
+ if (!l_PluginInit)
+ return M64ERR_NOT_INIT;
+
+ ///* reset some local variable */
+ l_DebugCallback = NULL;
+ l_DebugCallContext = NULL;
+
+ l_PluginInit = 0;
+ return M64ERR_SUCCESS;
+ }
+
+ EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities)
+ {
+ /* set version info */
+ if (PluginType != NULL)
+ *PluginType = M64PLUGIN_RSP;
+
+ if (PluginVersion != NULL)
+ *PluginVersion = RSP_Z64_VERSION;
+
+ if (APIVersion != NULL)
+ *APIVersion = RSP_PLUGIN_API_VERSION;
+
+ if (PluginNamePtr != NULL)
+ *PluginNamePtr = "Z64 RSP Plugin";
+
+ if (Capabilities != NULL)
+ {
+ *Capabilities = 0;
+ }
+
+ return M64ERR_SUCCESS;
+ }
+
+ EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles)
+ {
+ //#define VIDEO_HLE_ALLOWED
+ //#define AUDIO_HLE_ALLOWED
+
+#if defined (AUDIO_HLE_ALLOWED) || defined (VIDEO_HLE_ALLOWED)
+ unsigned int TaskType = *(unsigned int *)(z64_rspinfo.DMEM + 0xFC0);
+#endif
+
+#ifdef VIDEO_HLE_ALLOWED
+#if 0
+ if (TaskType == 1) {
+ SDL_Event event;
+ while (SDL_PollEvent(&event)) {
+ switch (event.type) {
+ case SDL_KEYDOWN:
+ switch (event.key.keysym.sym) {
+ case 'd':
+ printf("Dumping !\n");
+ dump();
+ break;
+ }
+ break;
+ }
+ }
+ }
+#endif
+
+ if (TaskType == 1) {
+ if (z64_rspinfo.ProcessDlistList != NULL) {
+ z64_rspinfo.ProcessDlistList();
+ }
+ *z64_rspinfo.SP_STATUS_REG |= (0x0203);
+ if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) {
+ *z64_rspinfo.MI_INTR_REG |= R4300i_SP_Intr;
+ z64_rspinfo.CheckInterrupts();
+ }
+
+ *z64_rspinfo.DPC_STATUS_REG &= ~0x0002;
+ return Cycles;
+ }
+#endif
+
+#ifdef AUDIO_HLE_ALLOWED
+ if (TaskType == 2) {
+ if (z64_rspinfo.ProcessAlistList != NULL) {
+ z64_rspinfo.ProcessAlistList();
+ }
+ *z64_rspinfo.SP_STATUS_REG |= (0x0203);
+ if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) {
+ *z64_rspinfo.MI_INTR_REG |= R4300i_SP_Intr;
+ z64_rspinfo.CheckInterrupts();
+ }
+ return Cycles;
+ }
+#endif
+
+ if (z64_rspinfo.CheckInterrupts==NULL)
+ log(M64MSG_WARNING, "Emulator doesn't provide CheckInterrupts routine");
+ return rsp_execute(0x100000);
+ //return Cycles;
+ }
+
+ EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount)
+ {
+ log(M64MSG_STATUS, "INITIATE RSP");
+ rsp_init(Rsp_Info);
+ memset(((UINT32*)z64_rspinfo.DMEM), 0, 0x2000);
+ //*CycleCount = 0; //Causes segfault, doesn't seem to be used anyway
+ }
+
+ EXPORT void CALL RomClosed(void)
+ {
+ extern int rsp_gen_cache_hit;
+ extern int rsp_gen_cache_miss;
+ log(M64MSG_STATUS, "cache hit %d miss %d %g%%", rsp_gen_cache_hit, rsp_gen_cache_miss,
+ rsp_gen_cache_miss*100.0f/rsp_gen_cache_hit);
+ rsp_gen_cache_hit = rsp_gen_cache_miss = 0;
+
+#ifdef RSPTIMING
+ int i,j;
+ UINT32 op, op2;
+
+ for(i=0; i<0x140;i++) {
+ if (i>=0x100)
+ op = (0x12<<26) | (0x10 << 21) | (i&0x3f);
+ else if (i>=0xc0)
+ op = (0x3a<<26) | ((i&0x1f)<<11);
+ else if (i>=0xa0)
+ op = (0x32<<26) | ((i&0x1f)<<11);
+ else if (i>=0x80)
+ op = (0x12<<26) | ((i&0x1f)<<21);
+ else if (i>=0x40)
+ op = (0<<26) | (i&0x3f);
+ else
+ op = (i&0x3f)<<26;
+
+ char s[128], s2[128];
+ rsp_dasm_one(s, 0x800, op);
+ //rsp_dasm_one(s2, 0x800, op2);
+ if (rsptimings[i])
+ printf("%10g %10g %7d\t%30s\n"
+ /*"%10g %10g %7d\t%30s\n"*/,
+ rsptimings[i]/(rspcounts[i]*1.0f), rsptimings[i]*(1.0f), rspcounts[i], s//,
+ //timings[k]/1.0f/counts[k], counts[k], s2
+ );
+ }
+#endif
+
+ //rsp_init(z64_rspinfo);
+ }
+#ifdef __cplusplus
+}
+#endif
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+/*
+Nintendo/SGI Reality Signal Processor (RSP) emulator
+
+Written by Ville Linde
+*/
+// #include "z64.h"
+#include "rsp.h"
+#include "rsp_opinfo.h"
+#include <math.h> // sqrt
+#include <assert.h>
+#include <string.h>
+
+#define INLINE inline
+
+#define LOG_INSTRUCTION_EXECUTION 0
+#define SAVE_DISASM 0
+#define SAVE_DMEM 0
+
+#define PRINT_VECREG(x) printf("V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X\n", (x), \
+ (UINT16)VREG_S((x),0), (UINT16)VREG_S((x),1), \
+ (UINT16)VREG_S((x),2), (UINT16)VREG_S((x),3), \
+ (UINT16)VREG_S((x),4), (UINT16)VREG_S((x),5), \
+ (UINT16)VREG_S((x),6), (UINT16)VREG_S((x),7))
+
+
+extern offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op);
+
+#if LOG_INSTRUCTION_EXECUTION
+static FILE *exec_output;
+#endif
+
+
+// INLINE void sp_set_status(UINT32 status)
+// {
+// if (status & 0x1)
+// {
+// cpu_trigger(6789);
+
+// cpunum_set_input_line(1, INPUT_LINE_HALT, ASSERT_LINE);
+// rsp_sp_status |= SP_STATUS_HALT;
+// }
+// if (status & 0x2)
+// {
+// rsp_sp_status |= SP_STATUS_BROKE;
+
+// if (rsp_sp_status & SP_STATUS_INTR_BREAK)
+// {
+// signal_rcp_interrupt(SP_INTERRUPT);
+// }
+// }
+// }
+
+
+#if 0
+enum
+{
+ RSP_PC = 1,
+ RSP_R0,
+ RSP_R1,
+ RSP_R2,
+ RSP_R3,
+ RSP_R4,
+ RSP_R5,
+ RSP_R6,
+ RSP_R7,
+ RSP_R8,
+ RSP_R9,
+ RSP_R10,
+ RSP_R11,
+ RSP_R12,
+ RSP_R13,
+ RSP_R14,
+ RSP_R15,
+ RSP_R16,
+ RSP_R17,
+ RSP_R18,
+ RSP_R19,
+ RSP_R20,
+ RSP_R21,
+ RSP_R22,
+ RSP_R23,
+ RSP_R24,
+ RSP_R25,
+ RSP_R26,
+ RSP_R27,
+ RSP_R28,
+ RSP_R29,
+ RSP_R30,
+ RSP_R31,
+};
+#endif
+
+
+#ifdef RSPTIMING
+uint64_t rsptimings[512];
+int rspcounts[512];
+#endif
+
+
+#define JUMP_ABS(addr) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); }
+#define JUMP_ABS_L(addr,l) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); rsp.r[l] = sp_pc + 4; }
+#define JUMP_REL(offset) { rsp.nextpc = 0x04001000 | ((sp_pc + ((offset) << 2)) & 0xfff); }
+#define JUMP_REL_L(offset,l) { rsp.nextpc = 0x04001000 | ((sp_pc + ((offset) << 2)) & 0xfff); rsp.r[l] = sp_pc + 4; }
+#define JUMP_PC(addr) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); }
+#define JUMP_PC_L(addr,l) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); rsp.r[l] = sp_pc + 4; }
+#define LINK(l) rsp.r[l] = sp_pc + 4
+
+
+#define VDREG ((op >> 6) & 0x1f)
+#define VS1REG ((op >> 11) & 0x1f)
+#define VS2REG ((op >> 16) & 0x1f)
+#define EL ((op >> 21) & 0xf)
+
+#define S_VREG_B(offset) (((15 - (offset)) & 0x07) << 3)
+#define S_VREG_S(offset) (((7 - (offset)) & 0x03) << 4)
+#define S_VREG_L(offset) (((3 - (offset)) & 0x01) << 5)
+
+#define M_VREG_B(offset) ((UINT64)0x00FF << S_VREG_B(offset))
+#define M_VREG_S(offset) ((UINT64)0x0000FFFFul << S_VREG_S(offset))
+#define M_VREG_L(offset) ((UINT64)0x00000000FFFFFFFFull << S_VREG_L(offset))
+
+#define R_VREG_B(reg, offset) ((rsp.v[(reg)].d[(15 - (offset)) >> 3] >> S_VREG_B(offset)) & 0x00FF)
+#define R_VREG_S(reg, offset) (INT16)((rsp.v[(reg)].d[(7 - (offset)) >> 2] >> S_VREG_S(offset)) & 0x0000FFFFul)
+#define R_VREG_L(reg, offset) ((rsp.v[(reg)].d[(3 - (offset)) >> 1] >> S_VREG_L(offset)) & 0x00000000FFFFFFFFull)
+
+#define W_VREG_B(reg, offset, val) (rsp.v[(reg)].d[(15 - (offset)) >> 3] = (rsp.v[(reg)].d[(15 - (offset)) >> 3] & ~M_VREG_B(offset)) | (M_VREG_B(offset) & ((UINT64)(val) << S_VREG_B(offset))))
+#define W_VREG_S(reg, offset, val) (rsp.v[(reg)].d[(7 - (offset)) >> 2] = (rsp.v[(reg)].d[(7 - (offset)) >> 2] & ~M_VREG_S(offset)) | (M_VREG_S(offset) & ((UINT64)(val) << S_VREG_S(offset))))
+#define W_VREG_L(reg, offset, val) (rsp.v[(reg)].d[(3 - (offset)) >> 1] = (rsp.v[(reg)].d[(3 - (offset)) >> 1] & ~M_VREG_L(offset)) | (M_VREG_L(offset) & ((UINT64)(val) << S_VREG_L(offset))))
+
+
+#define VEC_EL_1(x,z) (z)
+#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)])
+
+#define ACCUM(x) rsp.accum[((x))].q
+
+#define S_ACCUM_H (3 << 4)
+#define S_ACCUM_M (2 << 4)
+#define S_ACCUM_L (1 << 4)
+
+#define M_ACCUM_H (((INT64)0x0000FFFF) << S_ACCUM_H)
+#define M_ACCUM_M (((INT64)0x0000FFFF) << S_ACCUM_M)
+#define M_ACCUM_L (((INT64)0x0000FFFF) << S_ACCUM_L)
+
+#define R_ACCUM_H(x) ((INT16)((ACCUM(x) >> S_ACCUM_H) & 0x00FFFF))
+#define R_ACCUM_M(x) ((INT16)((ACCUM(x) >> S_ACCUM_M) & 0x00FFFF))
+#define R_ACCUM_L(x) ((INT16)((ACCUM(x) >> S_ACCUM_L) & 0x00FFFF))
+
+#define W_ACCUM_H(x, y) (ACCUM(x) = (ACCUM(x) & ~M_ACCUM_H) | (M_ACCUM_H & ((INT64)(y) << S_ACCUM_H)))
+#define W_ACCUM_M(x, y) (ACCUM(x) = (ACCUM(x) & ~M_ACCUM_M) | (M_ACCUM_M & ((INT64)(y) << S_ACCUM_M)))
+#define W_ACCUM_L(x, y) (ACCUM(x) = (ACCUM(x) & ~M_ACCUM_L) | (M_ACCUM_L & ((INT64)(y) << S_ACCUM_L)))
+
+
+
+RSP_REGS rsp;
+static int rsp_icount;
+// RSP Interface
+
+#define rsp_sp_status (*(UINT32*)z64_rspinfo.SP_STATUS_REG)
+#define sp_mem_addr (*(UINT32*)z64_rspinfo.SP_MEM_ADDR_REG)
+#define sp_dram_addr (*(UINT32*)z64_rspinfo.SP_DRAM_ADDR_REG)
+#define sp_semaphore (*(UINT32*)z64_rspinfo.SP_SEMAPHORE_REG)
+
+#define sp_dma_rlength (*(UINT32*)z64_rspinfo.SP_RD_LEN_REG)
+#define sp_dma_wlength (*(UINT32*)z64_rspinfo.SP_WR_LEN_REG)
+
+INT32 sp_dma_length;
+
+/*****************************************************************************/
+
+UINT32 get_cop0_reg(int reg)
+{
+ if (reg >= 0 && reg < 8)
+ {
+ return sp_read_reg(reg);
+ }
+ else if (reg >= 8 && reg < 16)
+ {
+ return n64_dp_reg_r(reg - 8, 0x00000000);
+ }
+ else
+ {
+ log(M64MSG_ERROR, "RSP: get_cop0_reg: %d", reg);
+ return ~0;
+ }
+}
+
+void set_cop0_reg(int reg, UINT32 data)
+{
+ if (reg >= 0 && reg < 8)
+ {
+ sp_write_reg(reg, data);
+ }
+ else if (reg >= 8 && reg < 16)
+ {
+ n64_dp_reg_w(reg - 8, data, 0x00000000);
+ }
+ else
+ {
+ log(M64MSG_ERROR, "RSP: set_cop0_reg: %d, %08X\n", reg, data);
+ }
+}
+
+static int got_unimp;
+void unimplemented_opcode(UINT32 op)
+{
+ got_unimp = 1;
+#ifdef MAME_DEBUG
+ char string[200];
+ rsp_dasm_one(string, rsp.ppc, op);
+ printf("%08X: %s\n", rsp.ppc, string);
+#endif
+
+#if SAVE_DISASM
+ {
+ char string[200];
+ int i;
+ FILE *dasm;
+ dasm = fopen("rsp_disasm.txt", "wt");
+
+ for (i=0; i < 0x1000; i+=4)
+ {
+ UINT32 opcode = ROPCODE(0x04001000 + i);
+ rsp_dasm_one(string, 0x04001000 + i, opcode);
+ fprintf(dasm, "%08X: %08X %s\n", 0x04001000 + i, opcode, string);
+ }
+ fclose(dasm);
+ }
+#endif
+#if SAVE_DMEM
+ {
+ int i;
+ FILE *dmem;
+ dmem = fopen("rsp_dmem.bin", "wb");
+
+ for (i=0; i < 0x1000; i++)
+ {
+ fputc(READ8(0x04000000 + i), dmem);
+ }
+ fclose(dmem);
+ }
+#endif
+
+ log(M64MSG_ERROR, "RSP: unknown opcode %02X (%d) (%08X) at %08X\n", op >> 26, op >> 26, op, rsp.ppc);
+}
+
+/*****************************************************************************/
+
+const int vector_elements_1[16][8] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // none
+ { 0, 1, 2, 3, 4, 5, 6 ,7 }, // ???
+ { 1, 3, 5, 7, 0, 2, 4, 6 }, // 0q
+ { 0, 2, 4, 6, 1, 3, 5, 7 }, // 1q
+ { 1, 2, 3, 5, 6, 7, 0, 4 }, // 0h
+ { 0, 2, 3, 4, 6, 7, 1, 5 }, // 1h
+ { 0, 1, 3, 4, 5, 7, 2, 6 }, // 2h
+ { 0, 1, 2, 4, 5, 6, 3, 7 }, // 3h
+ { 1, 2, 3, 4, 5, 6, 7, 0 }, // 0
+ { 0, 2, 3, 4, 5, 6, 7, 1 }, // 1
+ { 0, 1, 3, 4, 5, 6, 7, 2 }, // 2
+ { 0, 1, 2, 4, 5, 6, 7, 3 }, // 3
+ { 0, 1, 2, 3, 5, 6, 7, 4 }, // 4
+ { 0, 1, 2, 3, 4, 6, 7, 5 }, // 5
+ { 0, 1, 2, 3, 4, 5, 7, 6 }, // 6
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // 7
+};
+
+const int vector_elements_2[16][8] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // none
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // ???
+ { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q
+ { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q
+ { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h
+ { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h
+ { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h
+ { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
+ { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1
+ { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2
+ { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3
+ { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4
+ { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5
+ { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6
+ { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7
+};
+
+void rsp_init(RSP_INFO info)
+{
+#if LOG_INSTRUCTION_EXECUTION
+ exec_output = fopen("rsp_execute.txt", "wt");
+#endif
+
+ memset(&rsp, 0, sizeof(rsp));
+ rsp.ext = info;
+
+ sp_pc = 0; //0x4001000;
+ rsp.nextpc = ~0U;
+ //rsp_invalidate(0, 0x1000);
+ rsp.step_count=0;
+}
+
+void rsp_reset(void)
+{
+ rsp.nextpc = ~0U;
+}
+
+void handle_lwc2(UINT32 op)
+{
+ int i, end;
+ UINT32 ea;
+ int dest = (op >> 16) & 0x1f;
+ int base = (op >> 21) & 0x1f;
+ int index = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffffc0;
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: /* LBV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Load 1 byte to vector byte index
+
+ ea = (base) ? rsp.r[base] + offset : offset;
+ VREG_B(dest, index) = READ8(ea);
+ break;
+ }
+ case 0x01: /* LSV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 2 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 2) : (offset * 2);
+
+ end = index + 2;
+
+ // VP need mask i and ea ?
+ for (i=index; i < end; i++)
+ {
+ VREG_B(dest, i) = READ8(ea);
+ ea++;
+ }
+ break;
+ }
+ case 0x02: /* LLV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 4 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 4) : (offset * 4);
+
+ end = index + 4;
+
+ // VP need mask i and ea ?
+ for (i=index; i < end; i++)
+ {
+ VREG_B(dest, i) = READ8(ea);
+ ea++;
+ }
+ break;
+ }
+ case 0x03: /* LDV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads 8 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+
+ end = index + 8;
+
+ // VP need mask i and ea ?
+ for (i=index; i < end; i++)
+ {
+ VREG_B(dest, i) = READ8(ea);
+ ea++;
+ }
+ break;
+ }
+ case 0x04: /* LQV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00100 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads up to 16 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ end = index + (16 - (ea & 0xf));
+ if (end > 16) end = 16;
+ for (i=index; i < end; i++)
+ {
+ VREG_B(dest, i) = READ8(ea);
+ ea++;
+ }
+ break;
+ }
+ case 0x05: /* LRV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00101 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from right side until 16-byte boundary
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ index = 16 - ((ea & 0xf) - index);
+ end = 16;
+ ea &= ~0xf;
+ //assert(index == 0);
+
+ for (i=index; i < end; i++)
+ {
+ VREG_B(dest, i) = READ8(ea);
+ ea++;
+ }
+ break;
+ }
+ case 0x06: /* LPV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00110 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the upper 8 bits of each element
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+
+ for (i=0; i < 8; i++)
+ {
+ VREG_S(dest, i) = READ8(ea + (((16-index) + i) & 0xf)) << 8;
+ }
+ break;
+ }
+ case 0x07: /* LUV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 00111 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of each element
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+
+ for (i=0; i < 8; i++)
+ {
+ VREG_S(dest, i) = READ8(ea + (((16-index) + i) & 0xf)) << 7;
+ }
+ break;
+ }
+ case 0x08: /* LHV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of each element, with 2-byte stride
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ for (i=0; i < 8; i++)
+ {
+ VREG_S(dest, i) = READ8(ea + (((16-index) + (i<<1)) & 0xf)) << 7;
+ }
+ break;
+ }
+ case 0x09: /* LFV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads a byte as the bits 14-7 of upper or lower quad, with 4-byte stride
+
+ // fatalerror("RSP: LFV\n");
+
+ //if (index & 0x7) fatalerror("RSP: LFV: index = %d at %08X\n", index, rsp.ppc);
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ // not sure what happens if 16-byte boundary is crossed...
+ //if ((ea & 0xf) > 0) fatalerror("RSP: LFV: 16-byte boundary crossing at %08X, recheck this!\n", rsp.ppc);
+
+ end = (index >> 1) + 4;
+
+ for (i=index >> 1; i < end; i++)
+ {
+ VREG_S(dest, i) = READ8(ea) << 7;
+ ea += 4;
+ }
+ break;
+ }
+ case 0x0a: /* LWV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads the full 128-bit vector starting from vector byte index and wrapping to index 0
+ // after byte index 15
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ // not sure what happens if 16-byte boundary is crossed...
+ //if ((ea & 0xf) > 0) fatalerror("RSP: LWV: 16-byte boundary crossing at %08X, recheck this!\n", rsp.ppc);
+
+ end = (16 - index) + 16;
+
+ for (i=(16 - index); i < end; i++)
+ {
+ VREG_B(dest, i & 0xf) = READ8(ea);
+ ea += 4;
+ }
+ break;
+ }
+ case 0x0b: /* LTV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads one element to maximum of 8 vectors, while incrementing element index
+
+ // FIXME: has a small problem with odd indices
+
+ int element;
+ int vs = dest;
+ int ve = dest + 8;
+ if (ve > 32)
+ ve = 32;
+
+ element = 7 - (index >> 1);
+
+ //if (index & 1) fatalerror("RSP: LTV: index = %d\n", index);
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ ea = ((ea + 8) & ~0xf) + (index & 1);
+ for (i=vs; i < ve; i++)
+ {
+ element = ((8 - (index >> 1) + (i-vs)) << 1);
+ VREG_B(i, (element & 0xf)) = READ8(ea);
+ VREG_B(i, ((element+1) & 0xf)) = READ8(ea+1);
+
+ ea += 2;
+ }
+ break;
+ }
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+}
+
+void handle_swc2(UINT32 op)
+{
+ int i, end;
+ int eaoffset;
+ UINT32 ea;
+ int dest = (op >> 16) & 0x1f;
+ int base = (op >> 21) & 0x1f;
+ int index = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffffc0;
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: /* SBV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 1 byte from vector byte index
+
+ ea = (base) ? rsp.r[base] + offset : offset;
+ WRITE8(ea, VREG_B(dest, index));
+ break;
+ }
+ case 0x01: /* SSV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 2 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 2) : (offset * 2);
+
+ end = index + 2;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+ case 0x02: /* SLV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 4 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 4) : (offset * 4);
+
+ end = index + 4;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+ case 0x03: /* SDV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores 8 bytes starting from vector byte index
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+
+ end = index + 8;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, VREG_B(dest, i));
+ ea++;
+ }
+ break;
+ }
+ case 0x04: /* SQV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00100 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from vector byte index until 16-byte boundary
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ end = index + (16 - (ea & 0xf));
+ // if (end != 16)
+ // printf("SQV %d\n", end-index);
+ //assert(end == 16);
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, VREG_B(dest, i & 0xf));
+ ea++;
+ }
+ break;
+ }
+ case 0x05: /* SRV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00101 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores up to 16 bytes starting from right side until 16-byte boundary
+
+ int o;
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ end = index + (ea & 0xf);
+ o = (16 - (ea & 0xf)) & 0xf;
+ ea &= ~0xf;
+ // if (end != 16)
+ // printf("SRV %d\n", end-index);
+ //assert(end == 16);
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea, VREG_B(dest, ((i + o) & 0xf)));
+ ea++;
+ }
+ break;
+ }
+ case 0x06: /* SPV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00110 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores upper 8 bits of each element
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+ end = index + 8;
+
+ for (i=index; i < end; i++)
+ {
+ if ((i & 0xf) < 8)
+ {
+ WRITE8(ea, VREG_B(dest, ((i & 0xf) << 1)));
+ }
+ else
+ {
+ WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7);
+ }
+ ea++;
+ }
+ break;
+ }
+ case 0x07: /* SUV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 00111 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of each element
+
+ ea = (base) ? rsp.r[base] + (offset * 8) : (offset * 8);
+ end = index + 8;
+
+ for (i=index; i < end; i++)
+ {
+ if ((i & 0xf) < 8)
+ {
+ WRITE8(ea, VREG_S(dest, (i & 0x7)) >> 7);
+ }
+ else
+ {
+ WRITE8(ea, VREG_B(dest, ((i & 0x7) << 1)));
+ }
+ ea++;
+ }
+ break;
+ }
+ case 0x08: /* SHV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01000 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of each element, with 2-byte stride
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ for (i=0; i < 8; i++)
+ {
+ UINT8 d = ((VREG_B(dest, ((index + (i << 1) + 0) & 0xf))) << 1) |
+ ((VREG_B(dest, ((index + (i << 1) + 1) & 0xf))) >> 7);
+
+ WRITE8(ea, d);
+ ea += 2;
+ }
+ break;
+ }
+ case 0x09: /* SFV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01001 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores bits 14-7 of upper or lower quad, with 4-byte stride
+
+ // FIXME: only works for index 0 and index 8
+
+ if (index & 0x7)
+ log(M64MSG_WARNING, "SFV: index = %d at %08X\n", index, rsp.ppc);
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ eaoffset = ea & 0xf;
+ ea &= ~0xf;
+
+ end = (index >> 1) + 4;
+
+ for (i=index >> 1; i < end; i++)
+ {
+ WRITE8(ea + (eaoffset & 0xf), VREG_S(dest, i) >> 7);
+ eaoffset += 4;
+ }
+ break;
+ }
+ case 0x0a: /* SWV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01010 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores the full 128-bit vector starting from vector byte index and wrapping to index 0
+ // after byte index 15
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ eaoffset = ea & 0xf;
+ ea &= ~0xf;
+
+ end = index + 16;
+
+ for (i=index; i < end; i++)
+ {
+ WRITE8(ea + (eaoffset & 0xf), VREG_B(dest, i & 0xf));
+ eaoffset++;
+ }
+ break;
+ }
+ case 0x0b: /* STV */
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores one element from maximum of 8 vectors, while incrementing element index
+
+ int element, eaoffset;
+ int vs = dest;
+ int ve = dest + 8;
+ if (ve > 32)
+ ve = 32;
+
+ element = 8 - (index >> 1);
+ //if (index & 0x1) fatalerror("RSP: STV: index = %d at %08X\n", index, rsp.ppc);
+
+ ea = (base) ? rsp.r[base] + (offset * 16) : (offset * 16);
+
+ //if (ea & 0x1) fatalerror("RSP: STV: ea = %08X at %08X\n", ea, rsp.ppc);
+
+ eaoffset = (ea & 0xf) + (element * 2);
+ ea &= ~0xf;
+
+ for (i=vs; i < ve; i++)
+ {
+ WRITE16(ea + (eaoffset & 0xf), VREG_S(i, element & 0x7));
+ eaoffset += 2;
+ element++;
+ }
+ break;
+ }
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+}
+
+#define U16MIN 0x0000
+#define U16MAX 0xffff
+
+#define S16MIN 0x8000
+#define S16MAX 0x7fff
+
+INLINE UINT16 SATURATE_ACCUM_U(int accum)
+{
+ if ((INT16)ACCUM_H(accum) < 0)
+ {
+ if ((UINT16)(ACCUM_H(accum)) != 0xffff)
+ {
+ return U16MIN;
+ }
+ else
+ {
+ if ((INT16)ACCUM_M(accum) >= 0)
+ {
+ return U16MIN;
+ }
+ else
+ {
+ return ACCUM_L(accum);
+ }
+ }
+ }
+ else
+ {
+ if ((UINT16)(ACCUM_H(accum)) != 0)
+ {
+ return U16MAX;
+ }
+ else
+ {
+ if ((INT16)ACCUM_M(accum) < 0)
+ {
+ return U16MAX;
+ }
+ else
+ {
+ return ACCUM_L(accum);
+ }
+ }
+ }
+
+ return 0;
+}
+
+INLINE UINT16 SATURATE_ACCUM_S(int accum)
+{
+ if ((INT16)ACCUM_H(accum) < 0)
+ {
+ if ((UINT16)(ACCUM_H(accum)) != 0xffff)
+ return S16MIN;
+ else
+ {
+ if ((INT16)ACCUM_M(accum) >= 0)
+ return S16MIN;
+ else
+ return ACCUM_M(accum);
+ }
+ }
+ else
+ {
+ if ((UINT16)(ACCUM_H(accum)) != 0)
+ return S16MAX;
+ else
+ {
+ if ((INT16)ACCUM_M(accum) < 0)
+ return S16MAX;
+ else
+ return ACCUM_M(accum);
+ }
+ }
+
+ return 0;
+}
+
+#define WRITEBACK_RESULT() \
+ do { \
+ VREG_S(VDREG, 0) = vres[0]; \
+ VREG_S(VDREG, 1) = vres[1]; \
+ VREG_S(VDREG, 2) = vres[2]; \
+ VREG_S(VDREG, 3) = vres[3]; \
+ VREG_S(VDREG, 4) = vres[4]; \
+ VREG_S(VDREG, 5) = vres[5]; \
+ VREG_S(VDREG, 6) = vres[6]; \
+ VREG_S(VDREG, 7) = vres[7]; \
+ } while(0)
+
+
+void handle_vector_ops(UINT32 op)
+{
+ int i;
+ INT16 vres[8];
+
+ // Opcode legend:
+ // E = VS2 element type
+ // S = VS1, Source vector 1
+ // T = VS2, Source vector 2
+ // D = Destination vector
+
+ switch (op & 0x3f)
+ {
+ case 0x00: /* VMULF */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000000 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer * 2
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ if (s1 == -32768 && s2 == -32768)
+ {
+ // overflow
+ ACCUM_H(del) = 0;
+ ACCUM_M(del) = -32768;
+ ACCUM_L(del) = -32768;
+ vres[del] = 0x7fff;
+ }
+ else
+ {
+ INT64 r = s1 * s2 * 2;
+ r += 0x8000; // rounding ?
+ ACCUM_H(del) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit
+ ACCUM_M(del) = (INT16)(r >> 16);
+ ACCUM_L(del) = (UINT16)(r);
+ vres[del] = ACCUM_M(del);
+ }
+ }
+ WRITEBACK_RESULT();
+
+ break;
+ }
+
+ case 0x01: /* VMULU */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000001 |
+ // ------------------------------------------------------
+ //
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ INT64 r = s1 * s2 * 2;
+ r += 0x8000; // rounding ?
+
+ ACCUM_H(del) = (UINT16)(r >> 32);
+ ACCUM_M(del) = (UINT16)(r >> 16);
+ ACCUM_L(del) = (UINT16)(r);
+
+ if (r < 0)
+ {
+ vres[del] = 0;
+ }
+ else if (((INT16)(ACCUM_H(del)) ^ (INT16)(ACCUM_M(del))) < 0)
+ {
+ vres[del] = -1;
+ }
+ else
+ {
+ vres[del] = ACCUM_M(del);
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x04: /* VMUDL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000100 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by unsigned fraction
+ // Stores the higher 16 bits of the 32-bit result to accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, del);
+ UINT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel);
+ UINT32 r = s1 * s2;
+
+ ACCUM_H(del) = 0;
+ ACCUM_M(del) = 0;
+ ACCUM_L(del) = (UINT16)(r >> 16);
+
+ vres[del] = ACCUM_L(del);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x05: /* VMUDM */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000101 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by unsigned fraction
+ // The result is stored into accumulator
+ // The middle slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (UINT16)VREG_S(VS2REG, sel); // not sign-extended
+ INT32 r = s1 * s2;
+
+ ACCUM_H(del) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit
+ ACCUM_M(del) = (INT16)(r >> 16);
+ ACCUM_L(del) = (UINT16)(r);
+
+ vres[del] = ACCUM_M(del);
+ }
+ WRITEBACK_RESULT();
+ break;
+
+ }
+
+ case 0x06: /* VMUDN */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000110 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by signed integer
+ // The result is stored into accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT16)VREG_S(VS1REG, del); // not sign-extended
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ INT32 r = s1 * s2;
+
+ ACCUM_H(del) = (r < 0) ? 0xffff : 0; // sign-extend to 48-bit
+ ACCUM_M(del) = (INT16)(r >> 16);
+ ACCUM_L(del) = (UINT16)(r);
+
+ vres[del] = ACCUM_L(del);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x07: /* VMUDH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 000111 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer
+ // The result is stored into highest 32 bits of accumulator, the low slice is zero
+ // The highest 32 bits of accumulator is saturated into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ INT32 r = s1 * s2;
+
+ ACCUM_H(del) = (INT16)(r >> 16);
+ ACCUM_M(del) = (UINT16)(r);
+ ACCUM_L(del) = 0;
+
+ if (r < -32768) r = -32768;
+ if (r > 32767) r = 32767;
+ vres[del] = (INT16)(r);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x08: /* VMACF */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001000 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer * 2
+ // The result is added to accumulator
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ INT32 r = s1 * s2;
+
+ ACCUM(del) += (INT64)(r) << 17;
+ res = SATURATE_ACCUM_S(del);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x09: /* VMACU */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001001 |
+ // ------------------------------------------------------
+ //
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ INT32 r1 = s1 * s2;
+ UINT32 r2 = (UINT16)ACCUM_L(del) + ((UINT16)(r1) * 2);
+ UINT32 r3 = (UINT16)ACCUM_M(del) + (UINT16)((r1 >> 16) * 2) + (UINT16)(r2 >> 16);
+
+ ACCUM_L(del) = (UINT16)(r2);
+ ACCUM_M(del) = (UINT16)(r3);
+ ACCUM_H(del) += (UINT16)(r3 >> 16) + (UINT16)(r1 >> 31);
+
+ //res = SATURATE_ACCUM(del, 1, 0x0000, 0xffff);
+ if ((INT16)ACCUM_H(del) < 0)
+ {
+ res = 0;
+ }
+ else
+ {
+ if (ACCUM_H(del) != 0)
+ {
+ res = 0xffff;
+ }
+ else
+ {
+ if ((INT16)ACCUM_M(del) < 0)
+ {
+ res = 0xffff;
+ }
+ else
+ {
+ res = ACCUM_M(del);
+ }
+ }
+ }
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0c: /* VMADL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001100 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by unsigned fraction
+ // Adds the higher 16 bits of the 32-bit result to accumulator
+ // The low slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ UINT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, del);
+ UINT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel);
+ UINT32 r1 = s1 * s2;
+ UINT32 r2 = (UINT16)ACCUM_L(del) + (r1 >> 16);
+ UINT32 r3 = (UINT16)ACCUM_M(del) + (r2 >> 16);
+
+ ACCUM_L(del) = (UINT16)(r2);
+ ACCUM_M(del) = (UINT16)(r3);
+ ACCUM_H(del) += (INT16)(r3 >> 16);
+
+ res = SATURATE_ACCUM_U(del);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0d: /* VMADM */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001101 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by unsigned fraction
+ // The result is added into accumulator
+ // The middle slice of accumulator is stored into destination element
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ UINT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ UINT32 s2 = (UINT16)VREG_S(VS2REG, sel); // not sign-extended
+ UINT32 r1 = s1 * s2;
+ UINT32 r2 = (UINT16)ACCUM_L(del) + (UINT16)(r1);
+ UINT32 r3 = (UINT16)ACCUM_M(del) + (r1 >> 16) + (r2 >> 16);
+
+ ACCUM_L(del) = (UINT16)(r2);
+ ACCUM_M(del) = (UINT16)(r3);
+ ACCUM_H(del) += (UINT16)(r3 >> 16);
+ if ((INT32)(r1) < 0)
+ ACCUM_H(del) -= 1;
+
+ res = SATURATE_ACCUM_S(del);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x0e: /* VMADN */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001110 |
+ // ------------------------------------------------------
+ //
+ // Multiplies unsigned fraction by signed integer
+ // The result is added into accumulator
+ // The low slice of accumulator is stored into destination element
+
+#if 1
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT16)VREG_S(VS1REG, del); // not sign-extended
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ ACCUM(del) += (INT64)(s1*s2)<<16;
+ }
+
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ res = SATURATE_ACCUM_U(i);
+ //res = ACCUM_L(i);
+
+ VREG_S(VDREG, i) = res;
+ }
+#else
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT16)VREG_S(VS1REG, del); // not sign-extended
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ UINT32 r1 = s1 * s2;
+ UINT32 r2 = (UINT16)ACCUM_L(del) + (UINT16)(r1);
+ UINT32 r3 = (UINT16)ACCUM_M(del) + (r1 >> 16) + (r2 >> 16);
+
+ ACCUM_L(del) = (UINT16)(r2);
+ ACCUM_M(del) = (UINT16)(r3);
+ ACCUM_H(del) += (UINT16)(r3 >> 16);
+ if ((INT32)(r1) < 0)
+ ACCUM_H(del) -= 1;
+
+ res = SATURATE_ACCUM_U(del);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+#endif
+ break;
+ }
+
+ case 0x0f: /* VMADH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 001111 |
+ // ------------------------------------------------------
+ //
+ // Multiplies signed integer by signed integer
+ // The result is added into highest 32 bits of accumulator, the low slice is zero
+ // The highest 32 bits of accumulator is saturated into destination element
+
+#if 1
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+
+ rsp.accum[del].l[1] += s1*s2;
+
+ }
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ res = SATURATE_ACCUM_S(i);
+ //res = ACCUM_M(i);
+
+ VREG_S(VDREG, i) = res;
+ }
+#else
+ for (i=0; i < 8; i++)
+ {
+ UINT16 res;
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ INT64 r = s1 * s2;
+
+ ACCUM(del) += (INT64)(r) << 32;
+
+ res = SATURATE_ACCUM_S(del);
+
+ vres[del] = res;
+ }
+ WRITEBACK_RESULT();
+#endif
+ break;
+ }
+
+ case 0x10: /* VADD */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010000 |
+ // ------------------------------------------------------
+ //
+ // Adds two vector registers and carry flag, the result is saturated to 32767
+
+ // TODO: check VS2REG == VDREG
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ INT32 r = s1 + s2 + CARRY_FLAG(del);
+
+ ACCUM_L(del) = (INT16)(r);
+
+ if (r > 32767) r = 32767;
+ if (r < -32768) r = -32768;
+ vres[del] = (INT16)(r);
+ }
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x11: /* VSUB */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010001 |
+ // ------------------------------------------------------
+ //
+ // Subtracts two vector registers and carry flag, the result is saturated to -32768
+
+ // TODO: check VS2REG == VDREG
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (INT32)(INT16)VREG_S(VS1REG, del);
+ INT32 s2 = (INT32)(INT16)VREG_S(VS2REG, sel);
+ INT32 r = s1 - s2 - CARRY_FLAG(del);
+
+ ACCUM_L(del) = (INT16)(r);
+
+ if (r > 32767) r = 32767;
+ if (r < -32768) r = -32768;
+
+ vres[del] = (INT16)(r);
+ }
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x13: /* VABS */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010011 |
+ // ------------------------------------------------------
+ //
+ // Changes the sign of source register 2 if source register 1 is negative and stores
+ // the result to destination register
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT16 s1 = (INT16)VREG_S(VS1REG, del);
+ INT16 s2 = (INT16)VREG_S(VS2REG, sel);
+
+ if (s1 < 0)
+ {
+ if (s2 == -32768)
+ {
+ vres[del] = 32767;
+ }
+ else
+ {
+ vres[del] = -s2;
+ }
+ }
+ else if (s1 > 0)
+ {
+ vres[del] = s2;
+ }
+ else
+ {
+ vres[del] = 0;
+ }
+
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x14: /* VADDC */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010100 |
+ // ------------------------------------------------------
+ //
+ // Adds two vector registers, the carry out is stored into carry register
+
+ // TODO: check VS2REG = VDREG
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, del);
+ INT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel);
+ INT32 r = s1 + s2;
+
+ vres[del] = (INT16)(r);
+ ACCUM_L(del) = (INT16)(r);
+
+ if (r & 0xffff0000)
+ {
+ SET_CARRY_FLAG(del);
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x15: /* VSUBC */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 010101 |
+ // ------------------------------------------------------
+ //
+ // Subtracts two vector registers, the carry out is stored into carry register
+
+ // TODO: check VS2REG = VDREG
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT32 s1 = (UINT32)(UINT16)VREG_S(VS1REG, del);
+ INT32 s2 = (UINT32)(UINT16)VREG_S(VS2REG, sel);
+ INT32 r = s1 - s2;
+
+ vres[del] = (INT16)(r);
+ ACCUM_L(del) = (UINT16)(r);
+
+ if ((UINT16)(r) != 0)
+ {
+ SET_ZERO_FLAG(del);
+ }
+ if (r & 0xffff0000)
+ {
+ SET_CARRY_FLAG(del);
+ }
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x1d: /* VSAW */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 011101 |
+ // ------------------------------------------------------
+ //
+ // Stores high, middle or low slice of accumulator to destination vector
+
+ switch (EL)
+ {
+ case 0x08: // VSAWH
+ {
+ for (i=0; i < 8; i++)
+ {
+ VREG_S(VDREG, i) = ACCUM_H(i);
+ }
+ break;
+ }
+ case 0x09: // VSAWM
+ {
+ for (i=0; i < 8; i++)
+ {
+ VREG_S(VDREG, i) = ACCUM_M(i);
+ }
+ break;
+ }
+ case 0x0a: // VSAWL
+ {
+ for (i=0; i < 8; i++)
+ {
+ VREG_S(VDREG, i) = ACCUM_L(i);
+ }
+ break;
+ }
+ default: log(M64MSG_ERROR, "RSP: VSAW: el = %d\n", EL);
+ }
+ break;
+ }
+
+ case 0x20: /* VLT */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100000 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are less than VS2
+ // Moves the element in VS2 to destination vector
+
+ rsp.flag[1] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+
+ if (VREG_S(VS1REG, del) < VREG_S(VS2REG, sel))
+ {
+ vres[del] = VREG_S(VS1REG, del);
+ SET_COMPARE_FLAG(del);
+ }
+ else if (VREG_S(VS1REG, del) == VREG_S(VS2REG, sel))
+ {
+ vres[del] = VREG_S(VS1REG, del);
+ if (ZERO_FLAG(del) != 0 && CARRY_FLAG(del) != 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ else
+ {
+ vres[del] = VREG_S(VS2REG, sel);
+ }
+
+ ACCUM_L(del) = vres[del];
+ }
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x21: /* VEQ */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100001 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ rsp.flag[1] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+
+ vres[del] = VREG_S(VS2REG, sel);
+ ACCUM_L(del) = vres[del];
+
+ if (VREG_S(VS1REG, del) == VREG_S(VS2REG, sel))
+ {
+ if (ZERO_FLAG(del) == 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ }
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x22: /* VNE */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100010 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are not equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ rsp.flag[1] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+
+ vres[del] = VREG_S(VS1REG, del);
+ ACCUM_L(del) = vres[del];
+
+ if (VREG_S(VS1REG, del) != VREG_S(VS2REG, sel))
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ else
+ {
+ if (ZERO_FLAG(del) != 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ }
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x23: /* VGE */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100011 |
+ // ------------------------------------------------------
+ //
+ // Sets compare flags if elements in VS1 are greater or equal with VS2
+ // Moves the element in VS2 to destination vector
+
+ rsp.flag[1] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+
+ if (VREG_S(VS1REG, del) == VREG_S(VS2REG, sel))
+ {
+ if (ZERO_FLAG(del) == 0 || CARRY_FLAG(del) == 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ else if (VREG_S(VS1REG, del) > VREG_S(VS2REG, sel))
+ {
+ SET_COMPARE_FLAG(del);
+ }
+
+ if (COMPARE_FLAG(del) != 0)
+ {
+ vres[del] = VREG_S(VS1REG, del);
+ }
+ else
+ {
+ vres[del] = VREG_S(VS2REG, sel);
+ }
+
+ ACCUM_L(del) = vres[del];
+ }
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x24: /* VCL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100100 |
+ // ------------------------------------------------------
+ //
+ // Vector clip low
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT16 s1 = VREG_S(VS1REG, del);
+ INT16 s2 = VREG_S(VS2REG, sel);
+
+ if (CARRY_FLAG(del) != 0)
+ {
+ if (ZERO_FLAG(del) != 0)
+ {
+ if (COMPARE_FLAG(del) != 0)
+ {
+ ACCUM_L(del) = -(UINT16)s2;
+ }
+ else
+ {
+ ACCUM_L(del) = s1;
+ }
+ }
+ else
+ {
+ if (rsp.flag[2] & (1 << (del)))
+ {
+ if (((UINT32)(INT16)(s1) + (UINT32)(INT16)(s2)) > 0x10000)
+ {
+ ACCUM_L(del) = s1;
+ CLEAR_COMPARE_FLAG(del);
+ }
+ else
+ {
+ ACCUM_L(del) = -((UINT16)s2);
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ else
+ {
+ if (((UINT32)(INT16)(s1) + (UINT32)(INT16)(s2)) != 0)
+ {
+ ACCUM_L(del) = s1;
+ CLEAR_COMPARE_FLAG(del);
+ }
+ else
+ {
+ ACCUM_L(del) = -((UINT16)s2);
+ SET_COMPARE_FLAG(del);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (ZERO_FLAG(del) != 0)
+ {
+ if (rsp.flag[1] & (1 << (8+del)))
+ {
+ ACCUM_L(del) = s2;
+ }
+ else
+ {
+ ACCUM_L(del) = s1;
+ }
+ }
+ else
+ {
+ if (((INT32)(UINT16)s1 - (INT32)(UINT16)s2) >= 0)
+ {
+ ACCUM_L(del) = s2;
+ rsp.flag[1] |= (1 << (8+del));
+ }
+ else
+ {
+ ACCUM_L(del) = s1;
+ rsp.flag[1] &= ~(1 << (8+del));
+ }
+ }
+ }
+
+ vres[del] = ACCUM_L(del);
+ }
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ rsp.flag[2] = 0;
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x25: /* VCH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100101 |
+ // ------------------------------------------------------
+ //
+ // Vector clip high
+
+ CLEAR_ZERO_FLAGS();
+ CLEAR_CARRY_FLAGS();
+ rsp.flag[1] = 0;
+ rsp.flag[2] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT16 s1 = VREG_S(VS1REG, del);
+ INT16 s2 = VREG_S(VS2REG, sel);
+
+ if ((s1 ^ s2) < 0)
+ {
+ SET_CARRY_FLAG(del);
+ if (s2 < 0)
+ {
+ rsp.flag[1] |= (1 << (8+del));
+ }
+
+ if (s1 + s2 <= 0)
+ {
+ if (s1 + s2 == -1)
+ {
+ rsp.flag[2] |= (1 << (del));
+ }
+ SET_COMPARE_FLAG(del);
+ vres[del] = -((UINT16)s2);
+ }
+ else
+ {
+ vres[del] = s1;
+ }
+
+ if (s1 + s2 != 0)
+ {
+ if (s1 != ~s2)
+ {
+ SET_ZERO_FLAG(del);
+ }
+ }
+ }
+ else
+ {
+ if (s2 < 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ if (s1 - s2 >= 0)
+ {
+ rsp.flag[1] |= (1 << (8+del));
+ vres[del] = s2;
+ }
+ else
+ {
+ vres[del] = s1;
+ }
+
+ if ((s1 - s2) != 0)
+ {
+ if (s1 != ~s2)
+ {
+ SET_ZERO_FLAG(del);
+ }
+ }
+ }
+
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x26: /* VCR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100110 |
+ // ------------------------------------------------------
+ //
+ // Vector clip reverse
+
+ rsp.flag[0] = 0;
+ rsp.flag[1] = 0;
+ rsp.flag[2] = 0;
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ INT16 s1 = VREG_S(VS1REG, del);
+ INT16 s2 = VREG_S(VS2REG, sel);
+
+ if ((INT16)(s1 ^ s2) < 0)
+ {
+ if (s2 < 0)
+ {
+ rsp.flag[1] |= (1 << (8+del));
+ }
+ if ((s1 + s2) <= 0)
+ {
+ ACCUM_L(del) = ~((UINT16)s2);
+ SET_COMPARE_FLAG(del);
+ }
+ else
+ {
+ ACCUM_L(del) = s1;
+ }
+ }
+ else
+ {
+ if (s2 < 0)
+ {
+ SET_COMPARE_FLAG(del);
+ }
+ if ((s1 - s2) >= 0)
+ {
+ ACCUM_L(del) = s2;
+ rsp.flag[1] |= (1 << (8+del));
+ }
+ else
+ {
+ ACCUM_L(del) = s1;
+ }
+ }
+
+ vres[del] = ACCUM_L(del);
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x27: /* VMRG */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 100111 |
+ // ------------------------------------------------------
+ //
+ // Merges two vectors according to compare flags
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ if (COMPARE_FLAG(del) != 0)
+ {
+ vres[del] = VREG_S(VS1REG, del);
+ }
+ else
+ {
+ vres[del] = VREG_S(VS2REG, VEC_EL_2(EL, sel));
+ }
+
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x28: /* VAND */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101000 |
+ // ------------------------------------------------------
+ //
+ // Bitwise AND of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = VREG_S(VS1REG, del) & VREG_S(VS2REG, sel);
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x29: /* VNAND */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101001 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT AND of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = ~((VREG_S(VS1REG, del) & VREG_S(VS2REG, sel)));
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x2a: /* VOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101010 |
+ // ------------------------------------------------------
+ //
+ // Bitwise OR of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = VREG_S(VS1REG, del) | VREG_S(VS2REG, sel);
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x2b: /* VNOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101011 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT OR of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = ~((VREG_S(VS1REG, del) | VREG_S(VS2REG, sel)));
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x2c: /* VXOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101100 |
+ // ------------------------------------------------------
+ //
+ // Bitwise XOR of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = VREG_S(VS1REG, del) ^ VREG_S(VS2REG, sel);
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+ case 0x2d: /* VNXOR */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | TTTTT | DDDDD | 101101 |
+ // ------------------------------------------------------
+ //
+ // Bitwise NOT XOR of two vector registers
+
+ for (i=0; i < 8; i++)
+ {
+ int del = VEC_EL_1(EL, i);
+ int sel = VEC_EL_2(EL, del);
+ vres[del] = ~((VREG_S(VS1REG, del) ^ VREG_S(VS2REG, sel)));
+ ACCUM_L(del) = vres[del];
+ }
+ WRITEBACK_RESULT();
+ break;
+ }
+
+ case 0x30: /* VRCP */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110000 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal
+ int del = (VS1REG & 7);
+ int sel = EL&7; //VEC_EL_2(EL, del);
+ INT32 rec;
+
+ rec = (INT16)(VREG_S(VS2REG, sel));
+
+ if (rec == 0)
+ {
+ // divide by zero -> overflow
+ rec = 0x7fffffff;
+ }
+ else
+ {
+ int negative = 0;
+ if (rec < 0)
+ {
+ rec = ~rec+1;
+ negative = 1;
+ }
+ for (i = 15; i > 0; i--)
+ {
+ if (rec & (1 << i))
+ {
+ rec &= ((0xffc0) >> (15 - i));
+ i = 0;
+ }
+ }
+ rec = (INT32)(0x7fffffff / (double)rec);
+ for (i = 31; i > 0; i--)
+ {
+ if (rec & (1 << i))
+ {
+ rec &= ((0xffff8000) >> (31 - i));
+ i = 0;
+ }
+ }
+ if (negative)
+ {
+ rec = ~rec;
+ }
+ }
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ ACCUM_L(i) = VREG_S(VS2REG, element);
+ }
+
+ rsp.reciprocal_res = rec;
+
+ VREG_S(VDREG, del) = (UINT16)(rsp.reciprocal_res); // store low part
+ break;
+ }
+
+ case 0x31: /* VRCPL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110001 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal low part
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+ INT32 rec;
+
+ rec = ((UINT16)(VREG_S(VS2REG, sel)) | ((UINT32)(rsp.reciprocal_high) << 16));
+
+ if (rec == 0)
+ {
+ // divide by zero -> overflow
+ rec = 0x7fffffff;
+ }
+ else
+ {
+ int negative = 0;
+ if (rec < 0)
+ {
+ if (((UINT32)(rec & 0xffff0000) == 0xffff0000) && ((INT16)(rec & 0xffff) < 0))
+ {
+ rec = ~rec+1;
+ }
+ else
+ {
+ rec = ~rec;
+ }
+ negative = 1;
+ }
+ for (i = 31; i > 0; i--)
+ {
+ if (rec & (1 << i))
+ {
+ rec &= ((0xffc00000) >> (31 - i));
+ i = 0;
+ }
+ }
+ rec = (0x7fffffff / rec);
+ for (i = 31; i > 0; i--)
+ {
+ if (rec & (1 << i))
+ {
+ rec &= ((0xffff8000) >> (31 - i));
+ i = 0;
+ }
+ }
+ if (negative)
+ {
+ rec = ~rec;
+ }
+ }
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ ACCUM_L(i) = VREG_S(VS2REG, element);
+ }
+
+ rsp.reciprocal_res = rec;
+
+ VREG_S(VDREG, del) = (UINT16)(rsp.reciprocal_res); // store low part
+ break;
+ }
+
+ case 0x32: /* VRCPH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110010 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal high part
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+
+ rsp.reciprocal_high = VREG_S(VS2REG, sel);
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ ACCUM_L(i) = VREG_S(VS2REG, element); // perhaps accumulator is used to store the intermediate values ?
+ }
+
+ VREG_S(VDREG, del) = (INT16)(rsp.reciprocal_res >> 16); // store high part
+ break;
+ }
+
+ case 0x33: /* VMOV */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110011 |
+ // ------------------------------------------------------
+ //
+ // Moves element from vector to destination vector
+
+ int element = VS1REG & 7;
+ VREG_S(VDREG, element) = VREG_S(VS2REG, VEC_EL_2(EL, 7-element));
+ break;
+ }
+
+ case 0x35: /* VRSQL */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110101 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal square-root low part
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+ UINT32 sqr;
+
+ sqr = (UINT16)(VREG_S(VS2REG, sel)) | ((UINT32)(rsp.square_root_high) << 16);
+
+ if (sqr == 0)
+ {
+ // square root on 0 -> overflow
+ sqr = 0x7fffffff;
+ }
+ else if (sqr == 0xffff8000)
+ {
+ // overflow ?
+ sqr = 0xffff8000;
+ }
+ else
+ {
+ int negative = 0;
+ if (sqr > 0x7fffffff)
+ {
+ if (((UINT32)(sqr & 0xffff0000) == 0xffff0000) && ((INT16)(sqr & 0xffff) < 0))
+ {
+ sqr = ~sqr+1;
+ }
+ else
+ {
+ sqr = ~sqr;
+ }
+ negative = 1;
+ }
+ for (i = 31; i > 0; i--)
+ {
+ if (sqr & (1 << i))
+ {
+ sqr &= (0xff800000 >> (31 - i));
+ i = 0;
+ }
+ }
+ sqr = (INT32)(0x7fffffff / sqrt(sqr));
+ for (i = 31; i > 0; i--)
+ {
+ if (sqr & (1 << i))
+ {
+ sqr &= (0xffff8000 >> (31 - i));
+ i = 0;
+ }
+ }
+ if (negative)
+ {
+ sqr = ~sqr;
+ }
+ }
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ ACCUM_L(i) = VREG_S(VS2REG, element);
+ }
+
+ rsp.square_root_res = sqr;
+
+ VREG_S(VDREG, del) = (UINT16)(rsp.square_root_res); // store low part
+ break;
+ }
+
+ case 0x36: /* VRSQH */
+ {
+ // 31 25 24 20 15 10 5 0
+ // ------------------------------------------------------
+ // | 010010 | 1 | EEEE | SSSSS | ?FFFF | DDDDD | 110110 |
+ // ------------------------------------------------------
+ //
+ // Calculates reciprocal square-root high part
+
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+
+ rsp.square_root_high = VREG_S(VS2REG, sel);
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ ACCUM_L(i) = VREG_S(VS2REG, element); // perhaps accumulator is used to store the intermediate values ?
+ }
+
+ VREG_S(VDREG, del) = (INT16)(rsp.square_root_res >> 16); // store high part
+ break;
+ }
+
+ default: unimplemented_opcode(op); break;
+ }
+}
+
+int rsp_execute(int cycles)
+{
+ UINT32 op;
+
+ rsp_icount=1; //cycles;
+
+ UINT32 ExecutedCycles=0;
+ UINT32 BreakMarker=0;
+ UINT32 WDCHackFlag1=0;
+ UINT32 WDCHackFlag2=0;
+
+ sp_pc = /*0x4001000 | */(sp_pc & 0xfff);
+ if( rsp_sp_status & (SP_STATUS_HALT|SP_STATUS_BROKE))
+ {
+ log(M64MSG_WARNING, "Quit due to SP halt/broke on start");
+ rsp_icount = 0;
+ }
+
+
+ while (rsp_icount > 0)
+ {
+#ifdef RSPTIMING
+ uint64_t lasttime;
+ lasttime = RDTSC();
+#endif
+ rsp.ppc = sp_pc;
+
+
+ op = ROPCODE(sp_pc);
+#ifdef GENTRACE
+ char s[128];
+ rsp_dasm_one(s, sp_pc, op);
+ GENTRACE("%2x %3x\t%s\n", ((UINT8*)rsp_dmem)[0x1934], sp_pc, s);
+#endif
+
+ if (rsp.nextpc != ~0U)///DELAY SLOT USAGE
+ {
+ sp_pc = /*0x4001000 | */(rsp.nextpc & 0xfff); //rsp.nextpc;
+ rsp.nextpc = ~0U;
+ }
+ else
+ {
+ sp_pc = /*0x4001000 | */((sp_pc+4)&0xfff);
+ }
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ {
+ switch (op & 0x3f)
+ {
+ case 0x00: /* SLL */ if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break;
+ case 0x02: /* SRL */ if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break;
+ case 0x03: /* SRA */ if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break;
+ case 0x04: /* SLLV */ if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break;
+ case 0x06: /* SRLV */ if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break;
+ case 0x07: /* SRAV */ if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break;
+ case 0x08: /* JR */ JUMP_PC(RSVAL); break;
+ case 0x09: /* JALR */ JUMP_PC_L(RSVAL, RDREG); break;
+ case 0x0d: /* BREAK */
+ {
+ *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE );
+ if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) {
+ *z64_rspinfo.MI_INTR_REG |= 1;
+ z64_rspinfo.CheckInterrupts();
+ }
+ //sp_set_status(0x3);
+ rsp_icount = 0;
+
+ BreakMarker=1;
+
+#if LOG_INSTRUCTION_EXECUTION
+ fprintf(exec_output, "\n---------- break ----------\n\n");
+#endif
+ break;
+ }
+ case 0x20: /* ADD */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
+ case 0x21: /* ADDU */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
+ case 0x22: /* SUB */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
+ case 0x23: /* SUBU */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
+ case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break;
+ case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break;
+ case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break;
+ case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break;
+ case 0x2a: /* SLT */ if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break;
+ case 0x2b: /* SLTU */ if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break;
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x01: /* REGIMM */
+ {
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */ if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); break;
+ case 0x01: /* BGEZ */ if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break;
+ // VP according to the doc, link is performed even when condition fails,
+ // this sound pretty stupid but let's try it that way
+ case 0x11: /* BGEZAL */ LINK(31); if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break;
+ //case 0x11: /* BGEZAL */ if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break;
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x02: /* J */ JUMP_ABS(UIMM26); break;
+ case 0x03: /* JAL */ JUMP_ABS_L(UIMM26, 31); break;
+ case 0x04: /* BEQ */ if (RSVAL == RTVAL) JUMP_REL(SIMM16); break;
+ case 0x05: /* BNE */ if (RSVAL != RTVAL) JUMP_REL(SIMM16); break;
+ case 0x06: /* BLEZ */ if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); break;
+ case 0x07: /* BGTZ */ if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); break;
+ case 0x08: /* ADDI */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
+ case 0x09: /* ADDIU */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
+ case 0x0a: /* SLTI */ if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break;
+ case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break;
+ case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMM16; break;
+ case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMM16; break;
+ case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMM16; break;
+ case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMM16 << 16; break;
+
+ case 0x10: /* COP0 */
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC0 */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break;
+ case 0x04: /* MTC0 */ set_cop0_reg(RDREG, RTVAL); break;
+ default:
+ log(M64MSG_WARNING, "unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op);
+ break;
+ }
+ break;
+ }
+
+ case 0x12: /* COP2 */
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+
+ int el = (op >> 7) & 0xf;
+ UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf);
+ UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf);
+ if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2));
+ break;
+ }
+ case 0x02: /* CFC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ if (RTREG)
+ {
+ if (RDREG == 2)
+ {
+ // Anciliary clipping flags
+ RTVAL = rsp.flag[RDREG] & 0x00ff;
+ }
+ else
+ {
+ // All other flags are 16 bits but sign-extended at retrieval
+ RTVAL = (UINT32)rsp.flag[RDREG] | ( ( rsp.flag[RDREG] & 0x8000 ) ? 0xffff0000 : 0 );
+ }
+ }
+ break;
+
+ }
+ case 0x04: /* MTC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+
+ int el = (op >> 7) & 0xf;
+ VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff;
+ VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff;
+ break;
+ }
+ case 0x06: /* CTC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ rsp.flag[RDREG] = RTVAL & 0xffff;
+ break;
+ }
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ {
+ handle_vector_ops(op);
+ break;
+ }
+
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x20: /* LB */ if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break;
+ case 0x21: /* LH */ if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break;
+ case 0x23: /* LW */ if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break;
+ case 0x24: /* LBU */ if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break;
+ case 0x25: /* LHU */ if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break;
+ case 0x28: /* SB */ WRITE8(RSVAL + SIMM16, RTVAL); break;
+ case 0x29: /* SH */ WRITE16(RSVAL + SIMM16, RTVAL); break;
+ case 0x2b: /* SW */ WRITE32(RSVAL + SIMM16, RTVAL); break;
+ case 0x32: /* LWC2 */ handle_lwc2(op); break;
+ case 0x3a: /* SWC2 */ handle_swc2(op); break;
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+
+#ifdef RSPTIMING
+ uint64_t time = lasttime;
+ lasttime = RDTSC();
+ rsp_opinfo_t info;
+ rsp_get_opinfo(op, &info);
+ rsptimings[info.op2] += lasttime - time;
+ rspcounts[info.op2]++;
+#endif
+
+#if LOG_INSTRUCTION_EXECUTION
+ {
+ int i, l;
+ static UINT32 prev_regs[32];
+ static VECTOR_REG prev_vecs[32];
+ char string[200];
+ rsp_dasm_one(string, rsp.ppc, op);
+
+ fprintf(exec_output, "%08X: %s", rsp.ppc, string);
+
+ l = strlen(string);
+ if (l < 36)
+ {
+ for (i=l; i < 36; i++)
+ {
+ fprintf(exec_output, " ");
+ }
+ }
+
+ fprintf(exec_output, "| ");
+
+ for (i=0; i < 32; i++)
+ {
+ if (rsp.r[i] != prev_regs[i])
+ {
+ fprintf(exec_output, "R%d: %08X ", i, rsp.r[i]);
+ }
+ prev_regs[i] = rsp.r[i];
+ }
+
+ for (i=0; i < 32; i++)
+ {
+ if (rsp.v[i].d[0] != prev_vecs[i].d[0] || rsp.v[i].d[1] != prev_vecs[i].d[1])
+ {
+ fprintf(exec_output, "V%d: %04X|%04X|%04X|%04X|%04X|%04X|%04X|%04X ", i,
+ (UINT16)VREG_S(i,0), (UINT16)VREG_S(i,1), (UINT16)VREG_S(i,2), (UINT16)VREG_S(i,3), (UINT16)VREG_S(i,4), (UINT16)VREG_S(i,5), (UINT16)VREG_S(i,6), (UINT16)VREG_S(i,7));
+ }
+ prev_vecs[i].d[0] = rsp.v[i].d[0];
+ prev_vecs[i].d[1] = rsp.v[i].d[1];
+ }
+
+ fprintf(exec_output, "\n");
+
+ }
+#endif
+ // --rsp_icount;
+
+ ExecutedCycles++;
+ if( rsp_sp_status & SP_STATUS_SSTEP )
+ {
+ if( rsp.step_count )
+ {
+ rsp.step_count--;
+ }
+ else
+ {
+ rsp_sp_status |= SP_STATUS_BROKE;
+ }
+ }
+
+ if( rsp_sp_status & (SP_STATUS_HALT|SP_STATUS_BROKE))
+ {
+ rsp_icount = 0;
+
+ if(BreakMarker==0)
+ log(M64MSG_WARNING, "Quit due to SP halt/broke set by MTC0\n");
+ }
+
+ ///WDC&SR64 hack:VERSION3:1.8x -2x FASTER & safer
+ if((WDCHackFlag1==0)&&(rsp.ppc>0x137)&&(rsp.ppc<0x14D))
+ WDCHackFlag1=ExecutedCycles;
+ if ((WDCHackFlag1!=0)&&((rsp.ppc<=0x137)||(rsp.ppc>=0x14D)))
+ WDCHackFlag1=0;
+ if ((WDCHackFlag1!=0)&&((ExecutedCycles-WDCHackFlag1)>=0x20)&&(rsp.ppc>0x137)&&(rsp.ppc<0x14D))
+ {
+ // printf("WDC hack quit 1\n");
+ rsp_icount=0;//32 cycles should be enough
+ }
+ if((WDCHackFlag2==0)&&(rsp.ppc>0xFCB)&&(rsp.ppc<0xFD5))
+ WDCHackFlag2=ExecutedCycles;
+ if ((WDCHackFlag2!=0)&&((rsp.ppc<=0xFCB)||(rsp.ppc>=0xFD5)))
+ WDCHackFlag2=0;
+ if ((WDCHackFlag2!=0)&&((ExecutedCycles-WDCHackFlag2)>=0x20)&&(rsp.ppc>0xFCB)&&(rsp.ppc<0xFD5))
+ {
+ // printf("WDC hack quit 2\n");
+ rsp_icount=0;//32 cycles should be enough
+ }
+
+
+ }
+ //sp_pc -= 4;
+
+ return ExecutedCycles;
+}
+
+/*****************************************************************************/
+
+
+enum sp_dma_direction
+{
+ SP_DMA_RDRAM_TO_IDMEM,
+ SP_DMA_IDMEM_TO_RDRAM
+};
+
+static void sp_dma(enum sp_dma_direction direction)
+{
+ UINT8 *src, *dst;
+ int i, j;
+ int length;
+ int count;
+ int skip;
+
+
+ UINT32 l = sp_dma_length;
+ length = ((l & 0xfff) | 7) + 1;
+ skip = (l >> 20) + length;
+ count = ((l >> 12) & 0xff) + 1;
+
+ if (direction == SP_DMA_RDRAM_TO_IDMEM) // RDRAM -> I/DMEM
+ {
+ //UINT32 src_address = sp_dram_addr & ~7;
+ //UINT32 dst_address = (sp_mem_addr & 0x1000) ? 0x4001000 : 0x4000000;
+ src = (UINT8*)&rdram[(sp_dram_addr&~7) / 4];
+ dst = (sp_mem_addr & 0x1000) ? (UINT8*)&rsp_imem[(sp_mem_addr & ~7 & 0xfff) / 4] : (UINT8*)&rsp_dmem[(sp_mem_addr & ~7 &0xfff) / 4];
+ ///cpuintrf_push_context(0);
+#define BYTE8_XOR_BE(a) ((a)^7)// JFG, Ocarina of Time
+
+ for (j=0; j < count; j++)
+ {
+ for (i=0; i < length; i++)
+ {
+ ///UINT8 b = program_read_byte_64be(src_address + i + (j*skip));
+ ///program_write_byte_64be(dst_address + (((sp_mem_addr & ~7) + i + (j*length)) & 0xfff), b);
+ dst[BYTE8_XOR_BE((i + j*length)&0xfff)] = src[BYTE8_XOR_BE(i + j*skip)];
+ }
+ }
+
+ ///cpuintrf_pop_context();
+ *z64_rspinfo.SP_DMA_BUSY_REG = 0;
+ *z64_rspinfo.SP_STATUS_REG &= ~SP_STATUS_DMABUSY;
+ }
+ else if (direction == SP_DMA_IDMEM_TO_RDRAM) // I/DMEM -> RDRAM
+ {
+ //UINT32 dst_address = sp_dram_addr & ~7;
+ //UINT32 src_address = (sp_mem_addr & 0x1000) ? 0x4001000 : 0x4000000;
+
+ dst = (UINT8*)&rdram[(sp_dram_addr&~7) / 4];
+ src = (sp_mem_addr & 0x1000) ? (UINT8*)&rsp_imem[(sp_mem_addr & ~7 & 0xfff) / 4] : (UINT8*)&rsp_dmem[(sp_mem_addr & ~7 &0xfff) / 4];
+ ///cpuintrf_push_context(0);
+
+ for (j=0; j < count; j++)
+ {
+ for (i=0; i < length; i++)
+ {
+ ///UINT8 b = program_read_byte_64be(src_address + (((sp_mem_addr & ~7) + i + (j*length)) & 0xfff));
+ ///program_write_byte_64be(dst_address + i + (j*skip), b);
+ dst[BYTE8_XOR_BE(i + j*skip)] = src[BYTE8_XOR_BE((+i + j*length)&0xfff)];
+ }
+ }
+
+ ///cpuintrf_pop_context();
+ *z64_rspinfo.SP_DMA_BUSY_REG = 0;
+ *z64_rspinfo.SP_STATUS_REG &= ~SP_STATUS_DMABUSY;
+ }
+
+
+}
+
+
+
+
+
+UINT32 n64_sp_reg_r(UINT32 offset, UINT32 dummy)
+{
+ switch (offset)
+ {
+ case 0x00/4: // SP_MEM_ADDR_REG
+ return sp_mem_addr;
+
+ case 0x04/4: // SP_DRAM_ADDR_REG
+ return sp_dram_addr;
+
+ case 0x08/4: // SP_RD_LEN_REG
+ return sp_dma_rlength;
+
+ case 0x10/4: // SP_STATUS_REG
+ return rsp_sp_status;
+
+ case 0x14/4: // SP_DMA_FULL_REG
+ return 0;
+
+ case 0x18/4: // SP_DMA_BUSY_REG
+ return 0;
+
+ case 0x1c/4: // SP_SEMAPHORE_REG
+ return sp_semaphore;
+
+ default:
+ log(M64MSG_WARNING, "sp_reg_r: %08X\n", offset);
+ break;
+ }
+
+ return 0;
+}
+
+//UINT32 n64_sp_reg_w(RSP_REGS & rsp, UINT32 offset, UINT32 data, UINT32 dummy)
+void n64_sp_reg_w(UINT32 offset, UINT32 data, UINT32 dummy)
+{
+ UINT32 InterruptPending=0;
+ if ((offset & 0x10000) == 0)
+ {
+ switch (offset & 0xffff)
+ {
+ case 0x00/4: // SP_MEM_ADDR_REG
+ sp_mem_addr = data;
+ break;
+
+ case 0x04/4: // SP_DRAM_ADDR_REG
+ sp_dram_addr = data & 0xffffff;
+ break;
+
+ case 0x08/4: // SP_RD_LEN_REG
+ // sp_dma_length = data & 0xfff;
+ // sp_dma_count = (data >> 12) & 0xff;
+ // sp_dma_skip = (data >> 20) & 0xfff;
+ sp_dma_length=data;
+ sp_dma(SP_DMA_RDRAM_TO_IDMEM);
+ break;
+
+ case 0x0c/4: // SP_WR_LEN_REG
+ // sp_dma_length = data & 0xfff;
+ // sp_dma_count = (data >> 12) & 0xff;
+ // sp_dma_skip = (data >> 20) & 0xfff;
+ sp_dma_length=data;
+ sp_dma(SP_DMA_IDMEM_TO_RDRAM);
+ break;
+
+ case 0x10/4: // SP_STATUS_REG
+ {
+ if((data&0x1)&&(data&0x2))
+ log(M64MSG_ERROR, "Clear halt and set halt simultaneously\n");
+ if((data&0x8)&&(data&0x10))
+ log(M64MSG_ERROR, "Clear int and set int simultaneously\n");
+ if((data&0x20)&&(data&0x40))
+ log(M64MSG_ERROR, "Clear sstep and set sstep simultaneously\n");
+ if (data & 0x00000001) // clear halt
+ {
+ rsp_sp_status &= ~SP_STATUS_HALT;
+
+ // if (first_rsp)
+ // {
+ // cpu_spinuntil_trigger(6789);
+
+ // cpunum_set_input_line(1, INPUT_LINE_HALT, CLEAR_LINE);
+ // rsp_sp_status &= ~SP_STATUS_HALT;
+ // }
+ // else
+ // {
+ // first_rsp = 1;
+ // }
+ }
+ if (data & 0x00000002) // set halt
+ {
+ // cpunum_set_input_line(1, INPUT_LINE_HALT, ASSERT_LINE);
+ rsp_sp_status |= SP_STATUS_HALT;
+ }
+ if (data & 0x00000004) rsp_sp_status &= ~SP_STATUS_BROKE; // clear broke
+ if (data & 0x00000008) // clear interrupt
+ {
+ *z64_rspinfo.MI_INTR_REG &= ~R4300i_SP_Intr;
+ ///TEMPORARY COMMENTED FOR SPEED
+ /// printf("sp_reg_w clear interrupt");
+ //clear_rcp_interrupt(SP_INTERRUPT);
+ }
+ if (data & 0x00000010) // set interrupt
+ {
+ //signal_rcp_interrupt(SP_INTERRUPT);
+ }
+ if (data & 0x00000020) rsp_sp_status &= ~SP_STATUS_SSTEP; // clear single step
+ if (data & 0x00000040) {
+ rsp_sp_status |= SP_STATUS_SSTEP; // set single step
+ log(M64MSG_STATUS, "RSP STATUS REG: SSTEP set\n");
+ }
+ if (data & 0x00000080) rsp_sp_status &= ~SP_STATUS_INTR_BREAK; // clear interrupt on break
+ if (data & 0x00000100) rsp_sp_status |= SP_STATUS_INTR_BREAK; // set interrupt on break
+ if (data & 0x00000200) rsp_sp_status &= ~SP_STATUS_SIGNAL0; // clear signal 0
+ if (data & 0x00000400) rsp_sp_status |= SP_STATUS_SIGNAL0; // set signal 0
+ if (data & 0x00000800) rsp_sp_status &= ~SP_STATUS_SIGNAL1; // clear signal 1
+ if (data & 0x00001000) rsp_sp_status |= SP_STATUS_SIGNAL1; // set signal 1
+ if (data & 0x00002000) rsp_sp_status &= ~SP_STATUS_SIGNAL2; // clear signal 2
+ if (data & 0x00004000) rsp_sp_status |= SP_STATUS_SIGNAL2; // set signal 2
+ if (data & 0x00008000) rsp_sp_status &= ~SP_STATUS_SIGNAL3; // clear signal 3
+ if (data & 0x00010000) rsp_sp_status |= SP_STATUS_SIGNAL3; // set signal 3
+ if (data & 0x00020000) rsp_sp_status &= ~SP_STATUS_SIGNAL4; // clear signal 4
+ if (data & 0x00040000) rsp_sp_status |= SP_STATUS_SIGNAL4; // set signal 4
+ if (data & 0x00080000) rsp_sp_status &= ~SP_STATUS_SIGNAL5; // clear signal 5
+ if (data & 0x00100000) rsp_sp_status |= SP_STATUS_SIGNAL5; // set signal 5
+ if (data & 0x00200000) rsp_sp_status &= ~SP_STATUS_SIGNAL6; // clear signal 6
+ if (data & 0x00400000) rsp_sp_status |= SP_STATUS_SIGNAL6; // set signal 6
+ if (data & 0x00800000) rsp_sp_status &= ~SP_STATUS_SIGNAL7; // clear signal 7
+ if (data & 0x01000000) rsp_sp_status |= SP_STATUS_SIGNAL7; // set signal 7
+
+ if(InterruptPending==1)
+ {
+ *z64_rspinfo.MI_INTR_REG |= 1;
+ z64_rspinfo.CheckInterrupts();
+ InterruptPending=0;
+ }
+ break;
+ }
+
+ case 0x1c/4: // SP_SEMAPHORE_REG
+ sp_semaphore = data;
+ // mame_printf_debug("sp_semaphore = %08X\n", sp_semaphore);
+ break;
+
+ default:
+ log(M64MSG_WARNING, "sp_reg_w: %08X, %08X\n", data, offset);
+ break;
+ }
+ }
+ else
+ {
+ switch (offset & 0xffff)
+ {
+ case 0x00/4: // SP_PC_REG
+ //cpunum_set_info_int(1, CPUINFO_INT_PC, 0x04001000 | (data & 0xfff));
+ //break;
+
+ default:
+ log(M64MSG_WARNING, "sp_reg_w: %08X, %08X\n", data, offset);
+ break;
+ }
+ }
+}
+
+UINT32 sp_read_reg(UINT32 reg)
+{
+ switch (reg)
+ {
+ //case 4: return rsp_sp_status;
+ default: return n64_sp_reg_r(reg, 0x00000000);
+ }
+}
+
+
+void sp_write_reg(UINT32 reg, UINT32 data)
+{
+ switch (reg)
+ {
+ default: n64_sp_reg_w(reg, data, 0x00000000); break;
+ }
+}
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#ifndef _RSP_H_
+#define _RSP_H_
+
+#define M64P_PLUGIN_PROTOTYPES 1
+#include "m64p_types.h"
+#include "m64p_plugin.h"
+#include "z64.h"
+#include <math.h> // sqrt
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h> // memset
+
+#define INLINE inline
+
+extern void log(m64p_msg_level level, const char *msg, ...);
+
+/* defined in systems/n64.c */
+#define rdram ((UINT32*)z64_rspinfo.RDRAM)
+//extern UINT32 *rdram;
+#define rsp_imem ((UINT32*)z64_rspinfo.IMEM)
+//extern UINT32 *rsp_imem;
+#define rsp_dmem ((UINT32*)z64_rspinfo.DMEM)
+//extern UINT32 *rsp_dmem;
+//extern void dp_full_sync(void);
+
+#define vi_origin (*(UINT32*)z64_rspinfo.VI_ORIGIN_REG)
+//extern UINT32 vi_origin;
+#define vi_width (*(UINT32*)z64_rspinfo.VI_WIDTH_REG)
+//extern UINT32 vi_width;
+#define vi_control (*(UINT32*)z64_rspinfo.VI_STATUS_REG)
+//extern UINT32 vi_control;
+
+#define dp_start (*(UINT32*)z64_rspinfo.DPC_START_REG)
+//extern UINT32 dp_start;
+#define dp_end (*(UINT32*)z64_rspinfo.DPC_END_REG)
+//extern UINT32 dp_end;
+#define dp_current (*(UINT32*)z64_rspinfo.DPC_CURRENT_REG)
+//extern UINT32 dp_current;
+#define dp_status (*(UINT32*)z64_rspinfo.DPC_STATUS_REG)
+//extern UINT32 dp_status;
+
+#define sp_pc (*(UINT32*)z64_rspinfo.SP_PC_REG)
+
+typedef union
+{
+ UINT64 d[2];
+ UINT32 l[4];
+ INT16 s[8];
+ UINT8 b[16];
+} VECTOR_REG;
+
+typedef union
+{
+ INT64 q;
+ INT32 l[2];
+ INT16 w[4];
+} ACCUMULATOR_REG;
+
+typedef struct
+{
+ // vectors first , need to be memory aligned for sse
+ VECTOR_REG v[32];
+ ACCUMULATOR_REG accum[8];
+
+ //UINT32 pc;
+ UINT32 r[32];
+ UINT16 flag[4];
+
+ INT32 square_root_res;
+ INT32 square_root_high;
+ INT32 reciprocal_res;
+ INT32 reciprocal_high;
+
+ UINT32 ppc;
+ UINT32 nextpc;
+
+ UINT32 step_count;
+
+ int inval_gen;
+
+ RSP_INFO ext;
+} RSP_REGS;
+
+#define z64_rspinfo (rsp.ext)
+
+int rsp_execute(int cycles);
+void rsp_reset(void);
+void rsp_init(RSP_INFO info);
+offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op);
+
+extern UINT32 sp_read_reg(UINT32 reg);
+extern void sp_write_reg(UINT32 reg, UINT32 data);
+// extern READ32_HANDLER( n64_dp_reg_r );
+// extern WRITE32_HANDLER( n64_dp_reg_w );
+
+#define RSREG ((op >> 21) & 0x1f)
+#define RTREG ((op >> 16) & 0x1f)
+#define RDREG ((op >> 11) & 0x1f)
+#define SHIFT ((op >> 6) & 0x1f)
+
+#define RSVAL (rsp.r[RSREG])
+#define RTVAL (rsp.r[RTREG])
+#define RDVAL (rsp.r[RDREG])
+
+#define _RSREG(op) ((op >> 21) & 0x1f)
+#define _RTREG(op) ((op >> 16) & 0x1f)
+#define _RDREG(op) ((op >> 11) & 0x1f)
+#define _SHIFT(op) ((op >> 6) & 0x1f)
+
+#define _RSVAL(op) (rsp.r[_RSREG(op)])
+#define _RTVAL(op) (rsp.r[_RTREG(op)])
+#define _RDVAL(op) (rsp.r[_RDREG(op)])
+
+#define SIMM16 ((INT32)(INT16)(op))
+#define UIMM16 ((UINT16)(op))
+#define UIMM26 (op & 0x03ffffff)
+
+#define _SIMM16(op) ((INT32)(INT16)(op))
+#define _UIMM16(op) ((UINT16)(op))
+#define _UIMM26(op) (op & 0x03ffffff)
+
+
+/*#define _JUMP(pc) \
+if ((GENTRACE("_JUMP %x\n", rsp.nextpc), 1) && rsp_jump(rsp.nextpc)) return 1; \
+if (rsp.inval_gen || sp_pc != pc+8) return 0;
+*/
+
+#define CARRY_FLAG(x) ((rsp.flag[0] & (1 << ((x)))) ? 1 : 0)
+#define CLEAR_CARRY_FLAGS() { rsp.flag[0] &= ~0xff; }
+#define SET_CARRY_FLAG(x) { rsp.flag[0] |= (1 << ((x))); }
+#define CLEAR_CARRY_FLAG(x) { rsp.flag[0] &= ~(1 << ((x))); }
+
+#define COMPARE_FLAG(x) ((rsp.flag[1] & (1 << ((x)))) ? 1 : 0)
+#define CLEAR_COMPARE_FLAGS() { rsp.flag[1] &= ~0xff; }
+#define SET_COMPARE_FLAG(x) { rsp.flag[1] |= (1 << ((x))); }
+#define CLEAR_COMPARE_FLAG(x) { rsp.flag[1] &= ~(1 << ((x))); }
+
+#define ZERO_FLAG(x) ((rsp.flag[0] & (1 << (8+(x)))) ? 1 : 0)
+#define CLEAR_ZERO_FLAGS() { rsp.flag[0] &= ~0xff00; }
+#define SET_ZERO_FLAG(x) { rsp.flag[0] |= (1 << (8+(x))); }
+#define CLEAR_ZERO_FLAG(x) { rsp.flag[0] &= ~(1 << (8+(x))); }
+
+//#define rsp z64_rsp // to avoid namespace collision with other libs
+extern RSP_REGS rsp __attribute__((aligned(16)));
+
+
+//#define ROPCODE(pc) cpu_readop32(pc)
+#define ROPCODE(pc) program_read_dword_32be(pc | 0x1000)
+
+INLINE UINT8 program_read_byte_32be(UINT32 address)
+{
+ return ((UINT8*)z64_rspinfo.DMEM)[(address&0x1fff)^3];
+}
+
+INLINE UINT16 program_read_word_32be(UINT32 address)
+{
+ return ((UINT16*)z64_rspinfo.DMEM)[((address&0x1fff)>>1)^1];
+}
+
+INLINE UINT32 program_read_dword_32be(UINT32 address)
+{
+ return ((UINT32*)z64_rspinfo.DMEM)[(address&0x1fff)>>2];
+}
+
+INLINE void program_write_byte_32be(UINT32 address, UINT8 data)
+{
+ ((UINT8*)z64_rspinfo.DMEM)[(address&0x1fff)^3] = data;
+}
+
+INLINE void program_write_word_32be(UINT32 address, UINT16 data)
+{
+ ((UINT16*)z64_rspinfo.DMEM)[((address&0x1fff)>>1)^1] = data;
+}
+
+INLINE void program_write_dword_32be(UINT32 address, UINT32 data)
+{
+ ((UINT32*)z64_rspinfo.DMEM)[(address&0x1fff)>>2] = data;
+}
+
+INLINE UINT8 READ8(UINT32 address)
+{
+ address = 0x04000000 | (address & 0xfff);
+ return program_read_byte_32be(address);
+}
+
+INLINE UINT16 READ16(UINT32 address)
+{
+ address = 0x04000000 | (address & 0xfff);
+
+ if (address & 1)
+ {
+ //osd_die("RSP: READ16: unaligned %08X at %08X\n", address, rsp.ppc);
+ return ((program_read_byte_32be(address+0) & 0xff) << 8) | (program_read_byte_32be(address+1) & 0xff);
+ }
+
+ return program_read_word_32be(address);
+}
+
+INLINE UINT32 READ32(UINT32 address)
+{
+ address = 0x04000000 | (address & 0xfff);
+
+ if (address & 3)
+ {
+ //fatalerror("RSP: READ32: unaligned %08X at %08X\n", address, rsp.ppc);
+ return ((program_read_byte_32be(address + 0) & 0xff) << 24) |
+ ((program_read_byte_32be(address + 1) & 0xff) << 16) |
+ ((program_read_byte_32be(address + 2) & 0xff) << 8) |
+ ((program_read_byte_32be(address + 3) & 0xff) << 0);
+ }
+
+ return program_read_dword_32be(address);
+}
+
+
+INLINE void WRITE8(UINT32 address, UINT8 data)
+{
+ address = 0x04000000 | (address & 0xfff);
+ program_write_byte_32be(address, data);
+}
+
+INLINE void WRITE16(UINT32 address, UINT16 data)
+{
+ address = 0x04000000 | (address & 0xfff);
+
+ if (address & 1)
+ {
+ //fatalerror("RSP: WRITE16: unaligned %08X, %04X at %08X\n", address, data, rsp.ppc);
+ program_write_byte_32be(address + 0, (data >> 8) & 0xff);
+ program_write_byte_32be(address + 1, (data >> 0) & 0xff);
+ return;
+ }
+
+ program_write_word_32be(address, data);
+}
+
+INLINE void WRITE32(UINT32 address, UINT32 data)
+{
+ address = 0x04000000 | (address & 0xfff);
+
+ if (address & 3)
+ {
+ //fatalerror("RSP: WRITE32: unaligned %08X, %08X at %08X\n", address, data, rsp.ppc);
+ program_write_byte_32be(address + 0, (data >> 24) & 0xff);
+ program_write_byte_32be(address + 1, (data >> 16) & 0xff);
+ program_write_byte_32be(address + 2, (data >> 8) & 0xff);
+ program_write_byte_32be(address + 3, (data >> 0) & 0xff);
+ return;
+ }
+
+ program_write_dword_32be(address, data);
+}
+
+int rsp_jump(int pc);
+void rsp_invalidate(int begin, int len);
+void rsp_execute_one(UINT32 op);
+
+
+
+#define JUMP_ABS(addr) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); }
+#define JUMP_ABS_L(addr,l) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); rsp.r[l] = sp_pc + 4; }
+#define JUMP_REL(offset) { rsp.nextpc = 0x04001000 | ((sp_pc + ((offset) << 2)) & 0xfff); }
+#define JUMP_REL_L(offset,l) { rsp.nextpc = 0x04001000 | ((sp_pc + ((offset) << 2)) & 0xfff); rsp.r[l] = sp_pc + 4; }
+#define JUMP_PC(addr) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); }
+#define JUMP_PC_L(addr,l) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); rsp.r[l] = sp_pc + 4; }
+#define LINK(l) rsp.r[l] = sp_pc + 4
+
+#define VDREG ((op >> 6) & 0x1f)
+#define VS1REG ((op >> 11) & 0x1f)
+#define VS2REG ((op >> 16) & 0x1f)
+#define EL ((op >> 21) & 0xf)
+
+#define VREG_B(reg, offset) rsp.v[(reg)].b[((offset)^1)]
+#define VREG_S(reg, offset) rsp.v[(reg)].s[((offset))]
+#define VREG_L(reg, offset) rsp.v[(reg)].l[((offset))]
+
+#define VEC_EL_1(x,z) (z) //(vector_elements_1[(x)][(z)])
+#define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)])
+
+#define ACCUM(x) rsp.accum[((x))].q
+#define ACCUM_H(x) rsp.accum[((x))].w[3]
+#define ACCUM_M(x) rsp.accum[((x))].w[2]
+#define ACCUM_L(x) rsp.accum[((x))].w[1]
+
+void unimplemented_opcode(UINT32 op);
+void handle_vector_ops(UINT32 op);
+UINT32 get_cop0_reg(int reg);
+void set_cop0_reg(int reg, UINT32 data);
+void handle_lwc2(UINT32 op);
+void handle_swc2(UINT32 op);
+
+INLINE UINT32 n64_dp_reg_r(UINT32 offset, UINT32 dummy)
+{
+ switch (offset)
+ {
+ case 0x00/4: // DP_START_REG
+ return dp_start;
+
+ case 0x04/4: // DP_END_REG
+ return dp_end;
+
+ case 0x08/4: // DP_CURRENT_REG
+ return dp_current;
+
+ case 0x0c/4: // DP_STATUS_REG
+ return dp_status;
+
+ case 0x10/4: // DP_CLOCK_REG
+ return *z64_rspinfo.DPC_CLOCK_REG;
+
+ default:
+ log(M64MSG_WARNING, "dp_reg_r: %08X\n", offset);
+ break;
+ }
+
+ return 0;
+}
+INLINE void n64_dp_reg_w(UINT32 offset, UINT32 data, UINT32 dummy)
+{
+ switch (offset)
+ {
+ case 0x00/4: // DP_START_REG
+ dp_start = data;
+ dp_current = dp_start;
+ break;
+
+ case 0x04/4: // DP_END_REG
+ dp_end = data;
+ //rdp_process_list();
+ if (dp_end<dp_start)//three lines for debugging
+ {
+ log(M64MSG_INFO, "RDP End < RDP Start!");//happens in Stunt Racer with Ville Linde's sp_dma
+ break;
+ }
+ if (dp_end==dp_start)
+ break;
+ if (z64_rspinfo.ProcessRdpList != NULL) { z64_rspinfo.ProcessRdpList(); }
+ break;
+
+ case 0x0c/4: // DP_STATUS_REG
+ if (data & 0x00000001) dp_status &= ~DP_STATUS_XBUS_DMA;
+ if (data & 0x00000002) dp_status |= DP_STATUS_XBUS_DMA;
+ if (data & 0x00000004) dp_status &= ~DP_STATUS_FREEZE;
+ if (data & 0x00000008) dp_status |= DP_STATUS_FREEZE;
+ if (data & 0x00000010) dp_status &= ~DP_STATUS_FLUSH;
+ if (data & 0x00000020) dp_status |= DP_STATUS_FLUSH;
+ break;
+
+ default:
+ log(M64MSG_WARNING, "dp_reg_w: %08X, %08X\n", data, offset);
+ break;
+ }
+}
+
+#define INTEL86
+#if defined(INTEL86) && defined __GNUC__ && __GNUC__ >= 2
+static __inline__ unsigned long long RDTSC(void)
+{
+ unsigned long long int x;
+ __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
+ return x;
+}
+// inline volatile uint64_t RDTSC() {
+// register uint64_t TSC asm("eax");
+// asm volatile (".byte 15, 49" : : : "eax", "edx");
+// return TSC;
+// }
+// #define RDTSC1(n) __asm__ __volatile__("rdtsc" : "=a" (n): )
+// #define RDTSC2(n) __asm__ __volatile__ ("rdtsc\nmov %%edx,%%eax" : "=a" (n): )
+// inline void RDTSC(uint64_t& a) { uint32_t b, c; RDTSC1(b); RDTSC2(c);
+// a = (((uint64_t)c)<<32) | b; }
+#elif defined(INTEL86) && defined WIN32
+#define rdtsc __asm __emit 0fh __asm __emit 031h
+#define cpuid __asm __emit 0fh __asm __emit 0a2h
+inline uint64_t RDTSC() {
+ static uint32_t temp;
+ __asm {
+ push edx
+ push eax
+ rdtsc
+ mov temp, eax
+ pop eax
+ pop edx
+ }
+ return temp;
+}
+#else
+#define RDTSC(n) n=0
+#endif
+
+#ifdef GENTRACE
+#undef GENTRACE
+#include <stdarg.h>
+inline void GENTRACE(const char * s, ...) {
+ va_list ap;
+ va_start(ap, s);
+ vfprintf(stderr, s, ap);
+ va_end(ap);
+ int i;
+ for (i=0; i<32; i++)
+ fprintf(stderr, "r%d=%x ", i, rsp.r[i]);
+ fprintf(stderr, "\n");
+ for (i=0; i<32; i++)
+ fprintf(stderr, "v%d=%x %x %x %x %x %x %x %x ", i,
+ (UINT16)rsp.v[i].s[0],
+ (UINT16)rsp.v[i].s[1],
+ (UINT16)rsp.v[i].s[2],
+ (UINT16)rsp.v[i].s[3],
+ (UINT16)rsp.v[i].s[4],
+ (UINT16)rsp.v[i].s[5],
+ (UINT16)rsp.v[i].s[6],
+ (UINT16)rsp.v[i].s[7]
+ );
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "f0=%x f1=%x f2=%x f3=%x\n", rsp.flag[0],
+ rsp.flag[1],rsp.flag[2],rsp.flag[3]);
+}
+#endif
+//#define GENTRACE printf
+//#define GENTRACE
+
+#ifdef RSPTIMING
+extern uint64_t rsptimings[512];
+extern int rspcounts[512];
+#endif
+
+#endif // ifndef _RSP_H_
--- /dev/null
+{ global:
+PluginStartup;
+PluginShutdown;
+PluginGetVersion;
+DoRspCycles;
+InitiateRSP;
+RomClosed;
+local: *; };
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+/*
+ Nintendo/SGI RSP Disassembler
+
+ Written by Ville Linde
+*/
+
+//#include "z64.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include "rsp.h"
+
+#define DASMFLAG_SUPPORTED 0x80000000 /* are disassembly flags supported? */
+#define DASMFLAG_STEP_OUT 0x40000000 /* this instruction should be the end of a step out sequence */
+#define DASMFLAG_STEP_OVER 0x20000000 /* this instruction should be stepped over by setting a breakpoint afterwards */
+#define DASMFLAG_OVERINSTMASK 0x18000000 /* number of extra instructions to skip when stepping over */
+#define DASMFLAG_OVERINSTSHIFT 27 /* bits to shift after masking to get the value */
+#define DASMFLAG_LENGTHMASK 0x0000ffff /* the low 16-bits contain the actual length */
+#define DASMFLAG_STEP_OVER_EXTRA(x) ((x) << DASMFLAG_OVERINSTSHIFT)
+
+static const char *reg[32] =
+{
+ "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+};
+
+static const char *vreg[32] =
+{
+ " v0", " v1", " v2", " v3", " v4", " v5", " v6", " v7",
+ " v8", " v9", "v10", "v11", "v12", "v13", "v14", "v15",
+ "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+ "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
+};
+
+static const char *cop0_regs[32] =
+{
+ "SP_MEM_ADDR", "SP_DRAM_ADDR", "SP_RD_LEN", "SP_WR_LEN",
+ "SP_STATUS", "SP_DMA_FULL", "SP_DMA_BUSY", "SP_SEMAPHORE",
+ "DPC_START", "DPC_END", "DPC_CURRENT", "DPC_STATUS",
+ "DPC_CLOCK", "DPC_BUFBUSY", "DPC_PIPEBUSY", "DPC_TMEM",
+ "???", "???", "???", "???",
+ "???", "???", "???", "???",
+ "???", "???", "???", "???",
+ "???", "???", "???", "???"
+};
+
+static const char *element[16] =
+{
+ "", "[???]", "[00224466]", "[11335577]", "[00004444]", "[11115555]", "[22226666]", "[33337777]",
+ "[00000000]", "[11111111]", "[22222222]", "[33333333]", "[44444444]", "[55555555]", "[66666666]", "[77777777]"
+};
+
+static const char *element2[16] =
+{
+ "01234567", "????????", "00224466", "11335577", "00004444", "11115555", "22226666", "33337777",
+ "00000000", "11111111", "22222222", "33333333", "44444444", "55555555", "66666666", "77777777"
+};
+
+#define INLINE inline
+INLINE char *signed_imm16(UINT32 op)
+{
+ static char temp[10];
+ INT16 value = op & 0xffff;
+
+ if (value < 0)
+ {
+ sprintf(temp, "-$%04x", -value);
+ }
+ else
+ {
+ sprintf(temp, "$%04x", value);
+ }
+ return temp;
+}
+
+
+static char *output;
+
+static void print(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ output += vsprintf(output, fmt, vl);
+ va_end(vl);
+}
+
+static void disasm_cop0(UINT32 op)
+{
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: print("mfc0 %s, %s", reg[rt], cop0_regs[rd]); break;
+ case 0x04: print("mtc0 %s, %s", reg[rt], cop0_regs[rd]); break;
+
+ default: print("??? (COP0)"); break;
+ }
+}
+
+static void disasm_cop2(UINT32 op)
+{
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ int el = (op >> 21) & 0xf;
+ int dest = (op >> 6) & 0x1f;
+ int s1 = rd;
+ int s2 = rt;
+
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: print("mfc2 %s, %s[%d]", reg[rt], vreg[rd], dest); break;
+ case 0x02: print("cfc2 %s, FLAG%d", reg[rt], rd); break;
+ case 0x04: print("mtc2 %s, %s[%d]", reg[rt], vreg[rd], dest); break;
+ case 0x06: print("ctc2 %s, FLAG%d", reg[rt], rd); break;
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ {
+ switch (op & 0x3f)
+ {
+ case 0x00: print("vmulf %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x01: print("vmulu %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x02: print("vrndp %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x03: print("vmulq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x04: print("vmudl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x05: print("vmudm %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x06: print("vmudn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x07: print("vmudh %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x08: print("vmacf %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x09: print("vmacu %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0a: print("vrndn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0b: print("vmacq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0c: print("vmadl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0d: print("vmadm %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0e: print("vmadn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x0f: print("vmadh %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x10: print("vadd %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x11: print("vsub %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x12: print("vsut???"); break;
+ case 0x13: print("vabs %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x14: print("vaddc %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x15: print("vsubc %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+
+ case 0x1d:
+ {
+ switch (el)
+ {
+ case 8: print("vsaw %s, ACCUM_H", vreg[dest]); break;
+ case 9: print("vsaw %s, ACCUM_M", vreg[dest]); break;
+ case 10: print("vsaw %s, ACCUM_L", vreg[dest]); break;
+ default: print("vsaw %s, ???", vreg[dest]); break;
+ }
+ break;
+ }
+
+ case 0x20: print("vlt %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x21: print("veq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x22: print("vne %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x23: print("vge %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x24: print("vcl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x25: print("vch %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x26: print("vcr %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x27: print("vmrg %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x28: print("vand %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x29: print("vnand %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x2a: print("vor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x2b: print("vnor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x2c: print("vxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x2d: print("vnxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break;
+ case 0x30: print("vrcp %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x31: print("vrcpl %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x32: print("vrcph %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x33: print("vmov %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x34: print("vrsq %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x35: print("vrsql %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x36: print("vrsqh %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break;
+ case 0x37: print("vnop"); break;
+ default: print("??? (VECTOR OP)"); break;
+ }
+ break;
+ }
+
+ default: print("??? (COP2)"); break;
+ }
+}
+
+static void disasm_lwc2(UINT32 op)
+{
+ int dest = (op >> 16) & 0x1f;
+ int base = (op >> 21) & 0x1f;
+ int del = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffff80;
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: print("lbv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 1), reg[base]); break;
+ case 0x01: print("lsv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 2), reg[base]); break;
+ case 0x02: print("llv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 4), reg[base]); break;
+ case 0x03: print("ldv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x04: print("lqv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x05: print("lrv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x06: print("lpv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x07: print("luv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x08: print("lhv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x09: print("lfv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x0a: print("lwv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x0b: print("ltv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ default: print("??? (LWC2)"); break;
+ }
+}
+
+static void disasm_swc2(UINT32 op)
+{
+ int dest = (op >> 16) & 0x1f;
+ int base = (op >> 21) & 0x1f;
+ int del = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffff80;
+
+ switch ((op >> 11) & 0x1f)
+ {
+ case 0x00: print("sbv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 1), reg[base]); break;
+ case 0x01: print("ssv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 2), reg[base]); break;
+ case 0x02: print("slv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 4), reg[base]); break;
+ case 0x03: print("sdv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x04: print("sqv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x05: print("srv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x06: print("spv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x07: print("suv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break;
+ case 0x08: print("shv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x09: print("sfv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x0a: print("swv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ case 0x0b: print("stv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break;
+ default: print("??? (SWC2)"); break;
+ }
+}
+
+offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op)
+{
+ int rs = (op >> 21) & 31;
+ int rt = (op >> 16) & 31;
+ int rd = (op >> 11) & 31;
+ int shift = (op >> 6) & 31;
+ UINT32 flags = 0;
+
+ output = buffer;
+
+ switch (op >> 26)
+ {
+ case 0x00: // SPECIAL
+ {
+ switch (op & 0x3f)
+ {
+ case 0x00:
+ {
+ if (op == 0)
+ {
+ print("nop");
+ }
+ else
+ {
+ print("sll %s, %s, %d", reg[rd], reg[rt], shift);
+ }
+ break;
+ }
+ case 0x02: print("srl %s, %s, %d", reg[rd], reg[rt], shift); break;
+ case 0x03: print("sra %s, %s, %d", reg[rd], reg[rt], shift); break;
+ case 0x04: print("sllv %s, %s, %s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x06: print("srlv %s, %s, %s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x07: print("srav %s, %s, %s", reg[rd], reg[rt], reg[rs]); break;
+ case 0x08: print("jr %s", reg[rs]); if (rs == 31) flags = DASMFLAG_STEP_OUT; break;
+ case 0x09:
+ {
+ if (rd == 31)
+ {
+ print("jalr %s", reg[rs]);
+ }
+ else
+ {
+ print("jalr %s, %s", reg[rs], reg[rd]);
+ }
+ flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1);
+ break;
+ }
+ case 0x0d: print("break"); flags = DASMFLAG_STEP_OVER; break;
+ case 0x20: print("add %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x21: print("addu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x22: print("sub %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x23: print("subu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x24: print("and %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x25: print("or %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x26: print("xor %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x27: print("nor %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2a: print("slt %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+ case 0x2b: print("sltu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break;
+
+ default: print("???"); break;
+ }
+ break;
+ }
+
+ case 0x01: // REGIMM
+ {
+ switch ((op >> 16) & 0x1f)
+ {
+ case 0x00: print("bltz %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x01: print("bgez %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x10: print("bltzal %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+ case 0x11: print("bgezal %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break;
+
+ default: print("???"); break;
+ }
+ break;
+ }
+
+ case 0x02: print("j $%08X", (op & 0x03ffffff) << 2); break;
+ case 0x03: print("jal $%08X", (op & 0x03ffffff) << 2); break;
+ case 0x04: print("beq %s, %s, $%08X", reg[rs], reg[rt], pc + 4 + ((INT16)(op) << 2)); break;
+ case 0x05: print("bne %s, %s, $%08X", reg[rs], reg[rt], pc + 4 + ((INT16)(op) << 2)); break;
+ case 0x06: print("blez %s, $%08X", reg[rs], pc + 4 + ((INT16)(op) << 2)); break;
+ case 0x07: print("bgtz %s, $%08X", reg[rs], pc + 4 + ((INT16)(op) << 2)); break;
+ case 0x08: print("addi %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break;
+ case 0x09: print("addiu %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break;
+ case 0x0a: print("slti %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break;
+ case 0x0b: print("sltiu %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break;
+ case 0x0c: print("andi %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break;
+ case 0x0d: print("ori %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break;
+ case 0x0e: print("xori %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break;
+ case 0x0f: print("lui %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break;
+
+ case 0x10: disasm_cop0(op); break;
+ case 0x12: disasm_cop2(op); break;
+
+ case 0x20: print("lb %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x21: print("lh %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x23: print("lw %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x24: print("lbu %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x25: print("lhu %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x28: print("sb %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x29: print("sh %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+ case 0x2b: print("sw %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break;
+
+ case 0x32: disasm_lwc2(op); break;
+ case 0x3a: disasm_swc2(op); break;
+
+ default: print("???"); break;
+ }
+
+ return 4 | flags | DASMFLAG_SUPPORTED;
+}
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#include "rsp.h"
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <assert.h>
+
+#define GENDEBUG
+
+typedef int (* gen_f)(RSP_REGS & rsp);
+
+struct gen_t {
+ UINT32 crc;
+ void * lib;
+ gen_f f;
+#ifdef GENDEBUG
+ char name[32];
+#endif
+};
+
+struct opinfo_t {
+ int visit, labeled;
+ int label;
+
+ int nbgen;
+ int szgen;
+ gen_t * gentable;
+ gen_t * curgen;
+};
+
+struct branch_t {
+ int start, end;
+};
+
+static int curvisit;
+static opinfo_t opinfo[0x1000/4];
+static int nb_branches;
+static branch_t branches[256];
+static int nb_labels;
+static int labels[256];
+
+#define OPI(pc) opinfo[(pc)>>2]
+/*inline*/ void SETLABEL(int pc) {
+ //printf("%x\n", pc);
+ //pc &= 0xfff;
+ assert(pc >= 0 && pc < 0x1000);
+ if (OPI(pc).labeled != curvisit) {
+ labels[nb_labels] = pc;
+ OPI(pc).label = nb_labels++;
+ assert(nb_labels < sizeof(labels)/sizeof(labels[0]));
+ OPI(pc).labeled = curvisit;
+ }
+}
+
+#define ABS(addr) (((addr) << 2) & 0xfff)
+#define REL(offset) ((pc + ((offset) << 2)) & 0xfff)
+
+static UINT32 prep_gen(int pc, UINT32 crc, int & len)
+{
+ UINT32 op;
+ int br = 0;
+
+ branches[nb_branches].start = pc;
+
+ while ( !br )
+ {
+ if (OPI(pc).visit == curvisit) {
+ SETLABEL((pc)&0xfff);
+ SETLABEL((pc+4)&0xfff);
+ break;
+ }
+
+ OPI(pc).visit = curvisit;
+
+ op = ROPCODE(pc);
+ crc = ((crc<<1)|(crc>>31))^op^pc;
+ pc = (pc+4)&0xfff;
+ len++;
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ {
+ switch (op & 0x3f)
+ {
+ case 0x08: /* JR */
+ br = 1;
+ break;
+ case 0x09: /* JALR */
+ //br = 1;
+ break;
+ case 0x0d: /* BREAK */
+ br = 1;
+ break;
+ }
+ break;
+ }
+
+ case 0x01: /* REGIMM */
+ {
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */
+ case 0x01: /* BGEZ */
+ SETLABEL(REL(SIMM16));
+ break;
+ case 0x11: /* BGEZAL */
+ //br = 1;
+ break;
+ }
+ break;
+ }
+
+ case 0x02: /* J */
+ SETLABEL(ABS(UIMM26));
+ br = 1;
+ break;
+ case 0x04: /* BEQ */
+ case 0x05: /* BNE */
+ case 0x06: /* BLEZ */
+ case 0x07: /* BGTZ */
+ SETLABEL(REL(SIMM16));
+ break;
+ case 0x03: /* JAL */
+ //SETLABEL(ABS(UIMM26));
+ //br = 1;
+ break;
+ }
+
+ }
+
+ branches[nb_branches++].end = pc;
+ assert(nb_branches < sizeof(branches)/sizeof(branches[0]));
+
+ return crc;
+}
+
+static char tmps[1024];
+static char * delayed;
+static int has_cond;
+
+#define COND \
+ has_cond = 1, fprintf
+
+#define NOCOND() \
+ if (cont && OPI((pc+4)&0xfff).labeled == curvisit) { \
+ COND(fp, "cond = 1; \n"); \
+ } else \
+ has_cond = 0
+
+
+static void D_JUMP_ABS(UINT32 addr)
+{
+ int a = addr&0xfff;
+ sprintf(tmps, "%s { /*if (rsp.inval_gen) { rsp.nextpc=0x%x; return 0; }*/ %s goto L%d; }", has_cond? "if (cond)":"", a, has_cond? "cond=0; ":"", OPI(a).label);
+ delayed = tmps;
+}
+
+static void D_JUMP_REL(int pc, int offset)
+{
+ D_JUMP_ABS(pc+4 + ((offset) << 2));
+}
+
+static void D_JUMP()
+{
+ sprintf(tmps, "%s { return 0; }", has_cond? "if (cond)":"");
+ delayed = tmps;
+}
+
+static void D_JUMPL(int pc)
+{
+ sprintf(tmps,
+ "%s { \n"
+ "%s"
+ " int res;\n"
+ " if (res = rsp_jump(rsp.nextpc)) return res; \n"
+ " if (/*rsp.inval_gen || */sp_pc != 0x%x) return 0; \n"
+ "}", has_cond? "if (cond)":"", has_cond?" cond=0; \n":"", (pc+8)&0xfff);
+ delayed = tmps;
+ has_cond = 1;
+}
+
+static void dogen(const char * s, UINT32 op, FILE * fp)
+{
+ fprintf(fp, "#define op 0x%x\n%s\n#undef op\n", op, s);
+}
+
+#define GEN(s) dogen(s, op, fp)
+
+static void rsp_gen(int pc)
+{
+ int i;
+ const char * old_delayed;
+ int oldbr, br;
+
+ curvisit++;
+ if (!curvisit) {
+ // we looped, reset all visit counters
+ for (i=0; i<0x1000/4; i++) {
+ opinfo[i].visit = 0;
+ opinfo[i].labeled = 0;
+ }
+ curvisit++;
+ }
+
+ nb_branches = 0;
+ nb_labels = 0;
+
+ int len = 0;
+ UINT32 crc = prep_gen(pc, 0, len);
+
+ for (i=0; i<nb_labels; i++) {
+ if (OPI(labels[i]).visit != curvisit)
+ crc = prep_gen(labels[i], crc, len);
+ }
+
+ char src[128];
+ char lib[128];
+ char sym[128];
+ sprintf(lib, "z64/rspgen/%x-%x-%x.so", crc, pc, len);
+ sprintf(sym, "doit%x", crc);
+
+ opinfo_t * opi = &OPI(pc);
+ if (opi->gentable) {
+ for (i=0; i<opi->nbgen; i++)
+ if (opi->gentable[i].crc == crc) {
+ opi->curgen = opi->gentable + i;
+ return;
+ }
+ }
+ if (opi->nbgen >= opi->szgen) {
+ if (opi->szgen)
+ opi->szgen *= 2;
+ else
+ opi->szgen = 4;
+ opi->gentable = (gen_t *) realloc(opi->gentable, sizeof(gen_t)*(opi->szgen));
+ }
+ gen_t * gen;
+ gen = opi->gentable + opi->nbgen++;
+ opi->curgen = gen;
+
+#ifdef GENDEBUG
+ strcpy(gen->name, lib);
+#endif
+
+ gen->crc = crc;
+ gen->lib = dlopen(lib, RTLD_NOW);
+ if (gen->lib) {
+ gen->f = (gen_f) dlsym(gen->lib, sym);
+ assert(gen->f);
+ fprintf(stderr, "reloaded %s\n", lib);
+ return;
+ }
+ // else
+ // printf("%s\n", dlerror());
+
+ sprintf(src, "z64/rspgen/%x-%x-%x.cpp", crc, pc, len);
+ FILE * fp = fopen(src, "w");
+
+ fprintf(fp,
+ "#include \"rsp.h\"\n"
+ "\n"
+ "extern \"C\" {\n"
+ "int %s() {\n"
+ "int cond=0;\n",
+ sym);
+
+ for (i=0; i<nb_branches; i++) {
+ int cont = 1;
+ delayed = 0;
+ //fprintf(stderr, "branch %x --> %x\n", branches[i].start, branches[i].end-4);
+ for (pc=branches[i].start; cont || delayed; pc = (pc+4)&0xfff) {
+ UINT32 op = ROPCODE(pc);
+ char s[128];
+ rsp_dasm_one(s, pc, op);
+ if (cont && OPI(pc).labeled == curvisit)
+ fprintf(fp, "L%d: ;\n", OPI(pc).label);
+ //fprintf(fp, "/* %3x\t%s */\n", pc, s);
+ fprintf(fp, "GENTRACE(\"%3x\t%s\\n\");\n", pc, s);
+ oldbr = br;
+ br = 0;
+ old_delayed = delayed;
+ delayed = 0;
+
+ if (((pc+4)&0xfff)==branches[i].end)
+ cont = 0;
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ {
+ switch (op & 0x3f)
+ {
+ case 0x08: /* JR */
+ if (!old_delayed) {
+ br = 1|8|16;
+ NOCOND();
+ D_JUMP();
+ }
+ break;
+ case 0x09: /* JALR */
+ if (!old_delayed) {
+ br = 1;
+ NOCOND();
+ D_JUMPL(pc);
+ }
+ break;
+ case 0x0d: /* BREAK */
+ br = 2|8;
+ //delayed = "return 1;";
+ has_cond = 0;
+ break;
+ }
+ break;
+ }
+
+ case 0x01: /* REGIMM */
+ {
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */
+ if (!old_delayed) {
+ COND(fp, " cond=(INT32)(_RSVAL(0x%x)) < 0;\n", op);
+ D_JUMP_REL(pc, _SIMM16(op));
+ br = 4;
+ }
+ break;
+ case 0x01: /* BGEZ */
+ if (!old_delayed) {
+ COND(fp, " cond=(INT32)(_RSVAL(0x%x)) >= 0;\n", op);
+ D_JUMP_REL(pc, _SIMM16(op));
+ br = 4;
+ }
+ break;
+ case 0x11: /* BGEZAL */
+ br = 1;
+ COND(fp, "cond=(INT32)(_RSVAL(0x%x)) >= 0;\n", op);
+ D_JUMPL(pc);
+ break;
+ }
+ break;
+ }
+
+ case 0x02: /* J */
+ if (!old_delayed) {
+ NOCOND();
+ D_JUMP_ABS(_UIMM26(op) <<2);
+ br = 4|8|16;
+ }
+ break;
+ case 0x04: /* BEQ */
+ if (!old_delayed) {
+ COND(fp, " cond=_RSVAL(0x%0x) == _RTVAL(0x%0x);\n", op, op);
+ D_JUMP_REL(pc, _SIMM16(op));
+ br = 4;
+ }
+ break;
+ case 0x05: /* BNE */
+ if (!old_delayed) {
+ COND(fp, " cond=_RSVAL(0x%0x) != _RTVAL(0x%0x);\n", op, op);
+ D_JUMP_REL(pc, _SIMM16(op));
+ br = 4;
+ }
+ break;
+ case 0x06: /* BLEZ */
+ if (!old_delayed) {
+ COND(fp, " cond=(INT32)_RSVAL(0x%0x) <= 0;\n", op);
+ D_JUMP_REL(pc, _SIMM16(op));
+ br = 4;
+ }
+ break;
+ case 0x07: /* BGTZ */
+ if (!old_delayed) {
+ COND(fp, " cond=(INT32)_RSVAL(0x%0x) > 0;\n", op);
+ D_JUMP_REL(pc, _SIMM16(op));
+ br = 4;
+ }
+ break;
+ case 0x03: /* JAL */
+ if (!old_delayed) {
+ br = 1;
+ NOCOND();
+ D_JUMPL(pc);
+ }
+ break;
+ }
+
+ if (!(br&4) && (!old_delayed || !br)) {
+ if (br && !(br&16)) {
+ fprintf(fp, "sp_pc = 0x%x;\n", (pc + 4)&0xfff);
+ }
+ //fprintf(fp, "rsp_execute_one(0x%x);\n", op);
+
+
+
+
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ {
+ switch (op & 0x3f)
+ {
+ case 0x00: /* SLL */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL << SHIFT;"); break;
+ case 0x02: /* SRL */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL >> SHIFT; "); break;
+ case 0x03: /* SRA */ if (RDREG) GEN("RDVAL = (INT32)RTVAL >> SHIFT; "); break;
+ case 0x04: /* SLLV */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); "); break;
+ case 0x06: /* SRLV */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); "); break;
+ case 0x07: /* SRAV */ if (RDREG) GEN("RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); "); break;
+ case 0x08: /* JR */ GEN("JUMP_PC(RSVAL); "); break;
+ case 0x09: /* JALR */ GEN("JUMP_PC_L(RSVAL, RDREG); "); break;
+ case 0x0d: /* BREAK */
+ {
+ GEN(
+ " \
+ *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE ); \
+ if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { \
+ *z64_rspinfo.MI_INTR_REG |= 1; \
+ z64_rspinfo.CheckInterrupts(); \
+ } \
+ rsp.nextpc = ~0; \
+ return 1; \
+ ");
+ break;
+ }
+ case 0x20: /* ADD */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL + RTVAL); "); break;
+ case 0x21: /* ADDU */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL + RTVAL); "); break;
+ case 0x22: /* SUB */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL - RTVAL); "); break;
+ case 0x23: /* SUBU */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL - RTVAL); "); break;
+ case 0x24: /* AND */ if (RDREG) GEN("RDVAL = RSVAL & RTVAL; "); break;
+ case 0x25: /* OR */ if (RDREG) GEN("RDVAL = RSVAL | RTVAL; "); break;
+ case 0x26: /* XOR */ if (RDREG) GEN("RDVAL = RSVAL ^ RTVAL; "); break;
+ case 0x27: /* NOR */ if (RDREG) GEN("RDVAL = ~(RSVAL | RTVAL); "); break;
+ case 0x2a: /* SLT */ if (RDREG) GEN("RDVAL = (INT32)RSVAL < (INT32)RTVAL; "); break;
+ case 0x2b: /* SLTU */ if (RDREG) GEN("RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; "); break;
+ default: GEN("unimplemented_opcode(op); "); break;
+ }
+ break;
+ }
+
+ case 0x01: /* REGIMM */
+ {
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */ GEN("if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); "); break;
+ case 0x01: /* BGEZ */ GEN("if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); "); break;
+ // VP according to the doc, link is performed even when condition fails
+ case 0x11: /* BGEZAL */ GEN("LINK(31); if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); "); break;
+ //case 0x11: /* BGEZAL */ if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break;
+ default: GEN("unimplemented_opcode(op); "); break;
+ }
+ break;
+ }
+
+ case 0x02: /* J */ GEN("JUMP_ABS(UIMM26); "); break;
+ case 0x03: /* JAL */ GEN("JUMP_ABS_L(UIMM26, 31); "); break;
+ case 0x04: /* BEQ */ GEN("if (RSVAL == RTVAL) JUMP_REL(SIMM16); "); break;
+ case 0x05: /* BNE */ GEN("if (RSVAL != RTVAL) JUMP_REL(SIMM16); "); break;
+ case 0x06: /* BLEZ */ GEN("if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); "); break;
+ case 0x07: /* BGTZ */ GEN("if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); "); break;
+ case 0x08: /* ADDI */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL + SIMM16); "); break;
+ case 0x09: /* ADDIU */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL + SIMM16); "); break;
+ case 0x0a: /* SLTI */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); "); break;
+ case 0x0b: /* SLTIU */ if (RTREG) GEN("RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); "); break;
+ case 0x0c: /* ANDI */ if (RTREG) GEN("RTVAL = RSVAL & UIMM16; "); break;
+ case 0x0d: /* ORI */ if (RTREG) GEN("RTVAL = RSVAL | UIMM16; "); break;
+ case 0x0e: /* XORI */ if (RTREG) GEN("RTVAL = RSVAL ^ UIMM16; "); break;
+ case 0x0f: /* LUI */ if (RTREG) GEN("RTVAL = UIMM16 << 16; "); break;
+
+ case 0x10: /* COP0 */
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC0 */ if (RTREG) GEN("RTVAL = get_cop0_reg(rsp, RDREG); "); break;
+ case 0x04: /* MTC0 */
+ {
+ GEN("set_cop0_reg(rsp, RDREG, RTVAL); \n");
+ if (RDREG == 0x08/4) {
+ fprintf(fp,
+ "if (rsp.inval_gen) {\n"
+ " rsp.inval_gen = 0;\n"
+ " sp_pc = 0x%x; \n"
+ " return 2; \n"
+ "}\n"
+ , (pc + 4)&0xfff);
+ }
+ break;
+ }
+ default:
+ log(M64MSG_WARNING, "unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op);
+ break;
+ }
+ break;
+ }
+
+ case 0x12: /* COP2 */
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+ if (RTREG) GEN("\
+ {int el = (op >> 7) & 0xf;\
+ UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf);\
+ UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf);\
+ RTVAL = (INT32)(INT16)((b1 << 8) | (b2));}\
+ ");
+ break;
+ }
+ case 0x02: /* CFC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ // VP to sign extend or to not sign extend ?
+ //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG];
+ if (RTREG) GEN("RTVAL = rsp.flag[RDREG];");
+ break;
+ }
+ case 0x04: /* MTC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+ GEN("\
+ {int el = (op >> 7) & 0xf;\
+ VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff;\
+ VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff;}\
+ ");
+ break;
+ }
+ case 0x06: /* CTC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ GEN("rsp.flag[RDREG] = RTVAL & 0xffff;");
+ break;
+ }
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ {
+ GEN("handle_vector_ops(rsp, op);");
+ break;
+ }
+
+ default: GEN("unimplemented_opcode(op); "); break;
+ }
+ break;
+ }
+
+ case 0x20: /* LB */ if (RTREG) GEN("RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); "); break;
+ case 0x21: /* LH */ if (RTREG) GEN("RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); "); break;
+ case 0x23: /* LW */ if (RTREG) GEN("RTVAL = READ32(RSVAL + SIMM16); "); break;
+ case 0x24: /* LBU */ if (RTREG) GEN("RTVAL = (UINT8)READ8(RSVAL + SIMM16); "); break;
+ case 0x25: /* LHU */ if (RTREG) GEN("RTVAL = (UINT16)READ16(RSVAL + SIMM16); "); break;
+ case 0x28: /* SB */ GEN("WRITE8(RSVAL + SIMM16, RTVAL); "); break;
+ case 0x29: /* SH */ GEN("WRITE16(RSVAL + SIMM16, RTVAL); "); break;
+ case 0x2b: /* SW */ GEN("WRITE32(RSVAL + SIMM16, RTVAL); "); break;
+ case 0x32: /* LWC2 */ GEN("handle_lwc2(rsp, op); "); break;
+ case 0x3a: /* SWC2 */ GEN("handle_swc2(rsp, op); "); break;
+
+ default:
+ {
+ GEN("unimplemented_opcode(op);");
+ break;
+ }
+ }
+
+
+
+
+ // if (br) {
+ // if (br & 2)
+ // fprintf(fp, "return 1;\n");
+ // else
+ // fprintf(fp, "return 0;\n");
+ // }
+ }
+ if (old_delayed)
+ fprintf(fp, "%s\n", old_delayed);
+ }
+ if (!((/*br|*/oldbr)&8) && ((!oldbr && !(br&2)) || has_cond)) {
+ fprintf(fp, "/* jumping back to %x */\ngoto L%d;\n", pc, OPI(pc).label);
+ assert(OPI(pc).labeled == curvisit);
+ }
+ }
+
+ fprintf(fp, "}}\n");
+
+ fclose(fp);
+
+ pid_t pid = fork();
+ // SDL redirect these signals, but we need them untouched for waitpid call
+ signal(17, 0);
+ signal(11, 0);
+ if (!pid) {
+ // char s[128];
+ // atexit(0);
+ // sprintf(s, "gcc -Iz64 -g -shared -O2 %s -o %s", src, lib);
+ // system(s);
+ // exit(0);
+
+ //setsid();
+ //execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-g", "-O3", "-fomit-frame-pointer", src, "-o", lib, "-finline-limit=10000", 0);
+ //execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-O3", src, "-o", lib, "-fomit-frame-pointer", "-ffast-math", "-funroll-loops", "-fforce-addr", "-finline-limit=10000", 0);
+ //execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-O3", src, "-o", lib, "-fomit-frame-pointer", "-ffast-math", "-funroll-loops", "-fforce-addr", "-finline-limit=10000", "-m3dnow", "-mmmx", "-msse", "-msse2", "-mfpmath=sse", 0);
+ execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-O6", src, "-o", lib, "-fomit-frame-pointer", "-ffast-math", "-funroll-loops", "-fforce-addr", "-finline-limit=10000", "-m3dnow", "-mmmx", "-msse", "-msse2", 0);
+ printf("gnii ??\n");
+ exit(0);
+ }
+ waitpid(pid, 0, __WALL);
+
+ gen->lib = dlopen(lib, RTLD_NOW);
+ if (!gen->lib)
+ log(M64MSG_WARNING, "%s\n", dlerror());
+ assert(gen->lib);
+ log(M64MSG_VERBOSE, "created and loaded %s\n", lib);
+ gen->f = (gen_f) dlsym(gen->lib, sym);
+ assert(gen->f);
+}
+
+void rsp_invalidate(int begin, int len)
+{
+ //printf("invalidate %x %x\n", begin, len);
+ begin = 0; len = 0x1000;
+ assert(begin+len<=0x1000);
+ while (len > 0) {
+ OPI(begin).curgen = 0;
+ begin += 4;
+ len -= 4;
+ }
+ rsp.inval_gen = 1;
+}
+
+int rsp_jump(int pc)
+{
+ pc &= 0xfff;
+ sp_pc = pc;
+ rsp.nextpc = ~0;
+ opinfo_t * opi = &OPI(pc);
+ gen_t * gen = opi->curgen;
+ if (!gen) rsp_gen(pc);
+ gen = opi->curgen;
+ GENTRACE("rsp_jump %x (%s)\n", pc, gen->name);
+ int res = gen->f(rsp);
+ GENTRACE("r31 %x from %x nextpc %x pc %x res %d (%s)\n", rsp.r[31], pc, rsp.nextpc, sp_pc, res, gen->name);
+ if (rsp.nextpc != ~0)
+ {
+ sp_pc = (rsp.nextpc & 0xfff);
+ rsp.nextpc = ~0;
+ }
+ else
+ {
+ //sp_pc = ((sp_pc+4)&0xfff);
+ }
+ return res;
+}
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#include "rsp.h"
+
+inline UINT32 get_cop0_reg(RSP_REGS & rsp, int reg)
+{
+ if (reg >= 0 && reg < 8)
+ {
+ return sp_read_reg(rsp ,reg);
+ }
+ else if (reg >= 8 && reg < 16)
+ {
+ return n64_dp_reg_r(rsp, reg - 8, 0x00000000);
+ }
+ else
+ {
+ log(M64MSG_ERROR, "RSP: get_cop0_reg: %d", reg);
+ }
+}
+
+inline void set_cop0_reg(RSP_REGS & rsp, int reg, UINT32 data)
+{
+ if (reg >= 0 && reg < 8)
+ {
+ sp_write_reg(rsp, reg, data);
+ }
+ else if (reg >= 8 && reg < 16)
+ {
+ n64_dp_reg_w(rsp, reg - 8, data, 0x00000000);
+ }
+ else
+ {
+ log(M64MSG_ERROR, "RSP: set_cop0_reg: %d, %08X\n", reg, data);
+ }
+}
+
+static const int vector_elements_2[16][8] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // none
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // ???
+ { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q
+ { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q
+ { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h
+ { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h
+ { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h
+ { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
+ { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1
+ { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2
+ { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3
+ { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4
+ { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5
+ { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6
+ { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7
+};
+INLINE UINT16 SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive)
+{
+ if ((INT16)ACCUM_H(accum) < 0)
+ {
+ if ((UINT16)(ACCUM_H(accum)) != 0xffff)
+ {
+ return negative;
+ }
+ else
+ {
+ if ((INT16)ACCUM_M(accum) >= 0)
+ {
+ return negative;
+ }
+ else
+ {
+ if (slice == 0)
+ {
+ return ACCUM_L(accum);
+ }
+ else if (slice == 1)
+ {
+ return ACCUM_M(accum);
+ }
+ }
+ }
+ }
+ else
+ {
+ if ((UINT16)(ACCUM_H(accum)) != 0)
+ {
+ return positive;
+ }
+ else
+ {
+ if ((INT16)ACCUM_M(accum) < 0)
+ {
+ return positive;
+ }
+ else
+ {
+ if (slice == 0)
+ {
+ return ACCUM_L(accum);
+ }
+ else
+ {
+ return ACCUM_M(accum);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+INLINE UINT16 SATURATE_ACCUM1(int accum, UINT16 negative, UINT16 positive)
+{
+ if ((INT16)ACCUM_H(accum) < 0)
+ {
+ if ((UINT16)(ACCUM_H(accum)) != 0xffff)
+ return negative;
+ else
+ {
+ if ((INT16)ACCUM_M(accum) >= 0)
+ return negative;
+ else
+ return ACCUM_M(accum);
+ }
+ }
+ else
+ {
+ if ((UINT16)(ACCUM_H(accum)) != 0)
+ return positive;
+ else
+ {
+ if ((INT16)ACCUM_M(accum) < 0)
+ return positive;
+ else
+ return ACCUM_M(accum);
+ }
+ }
+
+ return 0;
+}
+
+#define WRITEBACK_RESULT() \
+ do { \
+ VREG_S(VDREG, 0) = vres[0]; \
+ VREG_S(VDREG, 1) = vres[1]; \
+ VREG_S(VDREG, 2) = vres[2]; \
+ VREG_S(VDREG, 3) = vres[3]; \
+ VREG_S(VDREG, 4) = vres[4]; \
+ VREG_S(VDREG, 5) = vres[5]; \
+ VREG_S(VDREG, 6) = vres[6]; \
+ VREG_S(VDREG, 7) = vres[7]; \
+ } while(0)
+
+#if 0
+inline void rsp_execute_one(UINT32 op)
+{
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ {
+ switch (op & 0x3f)
+ {
+ case 0x00: /* SLL */ if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break;
+ case 0x02: /* SRL */ if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break;
+ case 0x03: /* SRA */ if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break;
+ case 0x04: /* SLLV */ if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break;
+ case 0x06: /* SRLV */ if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break;
+ case 0x07: /* SRAV */ if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break;
+ case 0x08: /* JR */ JUMP_PC(RSVAL); break;
+ case 0x09: /* JALR */ JUMP_PC_L(RSVAL, RDREG); break;
+ case 0x0d: /* BREAK */
+ {
+ *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE );
+ if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) {
+ *z64_rspinfo.MI_INTR_REG |= 1;
+ z64_rspinfo.CheckInterrupts();
+ }
+ //sp_set_status(0x3);
+
+#if LOG_INSTRUCTION_EXECUTION
+ fprintf(exec_output, "\n---------- break ----------\n\n");
+#endif
+ break;
+ }
+ case 0x20: /* ADD */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
+ case 0x21: /* ADDU */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
+ case 0x22: /* SUB */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
+ case 0x23: /* SUBU */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
+ case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break;
+ case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break;
+ case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break;
+ case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break;
+ case 0x2a: /* SLT */ if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break;
+ case 0x2b: /* SLTU */ if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break;
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x01: /* REGIMM */
+ {
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */ if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); break;
+ case 0x01: /* BGEZ */ if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break;
+ // VP according to the doc, link is performed even when condition fails,
+ // this sound pretty stupid but let's try it that way
+ case 0x11: /* BGEZAL */ LINK(31); if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break;
+ //case 0x11: /* BGEZAL */ if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break;
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x02: /* J */ JUMP_ABS(UIMM26); break;
+ case 0x03: /* JAL */ JUMP_ABS_L(UIMM26, 31); break;
+ case 0x04: /* BEQ */ if (RSVAL == RTVAL) JUMP_REL(SIMM16); break;
+ case 0x05: /* BNE */ if (RSVAL != RTVAL) JUMP_REL(SIMM16); break;
+ case 0x06: /* BLEZ */ if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); break;
+ case 0x07: /* BGTZ */ if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); break;
+ case 0x08: /* ADDI */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
+ case 0x09: /* ADDIU */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
+ case 0x0a: /* SLTI */ if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break;
+ case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break;
+ case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMM16; break;
+ case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMM16; break;
+ case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMM16; break;
+ case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMM16 << 16; break;
+
+ case 0x10: /* COP0 */
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC0 */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break;
+ case 0x04: /* MTC0 */ set_cop0_reg(RDREG, RTVAL); break;
+ default:
+ printf("unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op);
+ break;
+ }
+ break;
+ }
+
+ case 0x12: /* COP2 */
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+
+ int el = (op >> 7) & 0xf;
+ UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf);
+ UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf);
+ if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2));
+ break;
+ }
+ case 0x02: /* CFC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ // VP to sign extend or to not sign extend ?
+ //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG];
+ if (RTREG) RTVAL = rsp.flag[RDREG];
+ break;
+ }
+ case 0x04: /* MTC2 */
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+
+ int el = (op >> 7) & 0xf;
+ VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff;
+ VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff;
+ break;
+ }
+ case 0x06: /* CTC2 */
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ rsp.flag[RDREG] = RTVAL & 0xffff;
+ break;
+ }
+
+ case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
+ case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ {
+ handle_vector_ops(op);
+ break;
+ }
+
+ default: unimplemented_opcode(op); break;
+ }
+ break;
+ }
+
+ case 0x20: /* LB */ if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break;
+ case 0x21: /* LH */ if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break;
+ case 0x23: /* LW */ if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break;
+ case 0x24: /* LBU */ if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break;
+ case 0x25: /* LHU */ if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break;
+ case 0x28: /* SB */ WRITE8(RSVAL + SIMM16, RTVAL); break;
+ case 0x29: /* SH */ WRITE16(RSVAL + SIMM16, RTVAL); break;
+ case 0x2b: /* SW */ WRITE32(RSVAL + SIMM16, RTVAL); break;
+ case 0x32: /* LWC2 */ handle_lwc2(op); break;
+ case 0x3a: /* SWC2 */ handle_swc2(op); break;
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+}
+
+#endif
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#include "rsp_opinfo.h"
+
+static const int vector_elements_2[16][8] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // none
+ { 0, 1, 2, 3, 4, 5, 6, 7 }, // ???
+ { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q
+ { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q
+ { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h
+ { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h
+ { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h
+ { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0
+ { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1
+ { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2
+ { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3
+ { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4
+ { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5
+ { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6
+ { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7
+};
+
+void rsp_get_opinfo(UINT32 op, rsp_opinfo_t * info)
+{
+ int op2;
+ int i;
+ info->op = op;
+ switch (op>>26) {
+ case 0: /* SPECIAL */
+ op2 = RSP_SPECIAL_OFFS + (op&0x3f);
+ break;
+ case 0x12: /* COP2 */
+ if (((op>>21)&0x1f) >= 0x10)
+ op2 = RSP_COP2_2_OFFS + (op & 0x3f);
+ else
+ op2 = RSP_COP2_1_OFFS + ((op >> 21) & 0x1f);
+ break;
+ case 0x32: /* LWC2 */
+ op2 = RSP_LWC2_OFFS + ((op>>11)&0x1f);
+ break;
+ case 0x3a: /* SWC2 */
+ op2 = RSP_SWC2_OFFS + ((op>>11)&0x1f);
+ break;
+ default:
+ op2 = RSP_BASIC_OFFS + (op>>26);
+ if (op2 == RSP_REGIMM) {
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */
+ op2 = RSP_BLTZ;
+ break;
+ case 0x01: /* BGEZ */
+ op2 = RSP_BGEZ;
+ break;
+ case 0x11: /* BGEZAL */
+ op2 = RSP_BGEZAL;
+ break;
+ }
+ }
+ }
+ info->op2 = op2;
+
+ memset(&info->used, 0, sizeof(info->used));
+ memset(&info->set, 0, sizeof(info->set));
+ info->used.accu = info->used.flag = 0;
+ info->set.accu = info->set.flag = 0;
+ info->flags = 0;
+
+ int dest = (op >> 16) & 0x1f;
+ int index = (op >> 7) & 0xf;
+ int offset = (op & 0x7f);
+ if (offset & 0x40)
+ offset |= 0xffffffc0;
+
+ switch(op2) {
+ case RSP_SPECIAL:
+ case RSP_BLTZ:
+ info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC;
+ break;
+ case RSP_BGEZ:
+ info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC;
+ break;
+ case RSP_BGEZAL:
+ info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_LINK | RSP_OPINFO_USEPC;
+ break;
+ case RSP_J:
+ info->flags = RSP_OPINFO_JUMP;
+ break;
+ case RSP_JAL:
+ info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_LINK | RSP_OPINFO_USEPC;
+ break;
+ case RSP_BEQ:
+ case RSP_BNE:
+ case RSP_BLEZ:
+ case RSP_BGTZ:
+ info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC;
+ break;
+ case RSP_ADDI:
+ case RSP_ADDIU:
+ case RSP_SLTI:
+ case RSP_SLTIU:
+ case RSP_ANDI:
+ case RSP_ORI:
+ case RSP_XORI:
+ case RSP_LUI:
+ case RSP_COP0:
+ case RSP_LB:
+ case RSP_LH:
+ case RSP_LW:
+ case RSP_LBU:
+ case RSP_LHU:
+ case RSP_SB:
+ case RSP_SH:
+ case RSP_SW:
+ break;
+
+ case RSP_SLL:
+ case RSP_SRL:
+ case RSP_SRA:
+ case RSP_SLLV:
+ case RSP_SRLV:
+ case RSP_SRAV:
+ break;
+
+ case RSP_JR:
+ info->flags = RSP_OPINFO_JUMP;
+ break;
+ case RSP_JALR:
+ info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_LINK | RSP_OPINFO_USEPC;
+ break;
+ case RSP_BREAK:
+ info->flags = RSP_OPINFO_BREAK;
+ break;
+
+ case RSP_ADD:
+ case RSP_ADDU:
+ case RSP_SUB:
+ case RSP_SUBU:
+ case RSP_AND:
+ case RSP_OR:
+ case RSP_XOR:
+ case RSP_NOR:
+ case RSP_SLT:
+ case RSP_SLTU:
+ break;
+
+ case RSP_MFC2:
+ {
+ int el = op >> 7;
+ RSP_SET_VEC_I(info->used, VS1REG, ((el+0)&0xf)>>1);
+ RSP_SET_VEC_I(info->used, VS1REG, ((el+1)&0xf)>>1);
+ break;
+ }
+ case RSP_CFC2:
+ RSP_SET_FLAG_I(info->used, RDREG & 3);
+ break;
+ case RSP_MTC2:
+ {
+ int el = op >> 7;
+ RSP_SET_VEC_I(info->set, VS1REG, ((el+0)&0xf)>>1);
+ RSP_SET_VEC_I(info->set, VS1REG, ((el+1)&0xf)>>1);
+ break;
+ }
+ case RSP_CTC2:
+ RSP_SET_FLAG_I(info->set, RDREG & 3);
+ break;
+
+
+ case RSP_LBV:
+ RSP_SET_VEC_I(info->set, dest, index>>1);
+ break;
+ case RSP_LSV:
+ for (i=index; i<index+2; i++)
+ RSP_SET_VEC_I(info->set, dest, (i>>1)&7);
+ break;
+ case RSP_LLV:
+ for (i=index; i<index+4; i++)
+ RSP_SET_VEC_I(info->set, dest, (i>>1)&7);
+ break;
+ case RSP_LDV:
+ for (i=index; i<index+8; i++)
+ RSP_SET_VEC_I(info->set, dest, (i>>1)&7);
+ break;
+ case RSP_LQV:
+ case RSP_LRV:
+ // WARNING WARNING WARNING
+ // we assume this instruction always used to load the full vector
+ // i.e. the address is always 16 bytes aligned
+ // for (i=0; i<8; i++)
+ // RSP_SET_VEC_I(info->set, dest, i);
+ break;
+ case RSP_LPV:
+ case RSP_LUV:
+ case RSP_LHV:
+ case RSP_LWV:
+ for (i=0; i<8; i++)
+ RSP_SET_VEC_I(info->set, dest, i);
+ break;
+ case RSP_LFV:
+ for (i=(index>>1); i<(index>>1)+4; i++)
+ RSP_SET_VEC_I(info->set, dest, i);
+ break;
+ case RSP_LTV:
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Loads one element to maximum of 8 vectors, while incrementing element index
+
+ // FIXME: has a small problem with odd indices
+
+ int element;
+ int vs = dest;
+ int ve = dest + 8;
+ if (ve > 32)
+ ve = 32;
+
+ element = 7 - (index >> 1);
+
+ if (index & 1)
+ log(M64MSG_ERROR, "RSP: LTV: index = %d\n", index);
+
+ for (i=vs; i < ve; i++)
+ {
+ element = ((8 - (index >> 1) + (i-vs)) << 1);
+ RSP_SET_VEC_I(info->set, i, (element & 0xf)>>1);
+ RSP_SET_VEC_I(info->set, i, ((element+1) & 0xf)>>1);
+ }
+ break;
+ }
+
+ case RSP_SBV:
+ RSP_SET_VEC_I(info->used, dest, index>>1);
+ break;
+ case RSP_SSV:
+ for (i=index; i<index+2; i++)
+ RSP_SET_VEC_I(info->used, dest, (i>>1)&7);
+ break;
+ case RSP_SLV:
+ for (i=index; i<index+4; i++)
+ RSP_SET_VEC_I(info->used, dest, (i>>1)&7);
+ break;
+ case RSP_SDV:
+ for (i=index; i<index+8; i++)
+ RSP_SET_VEC_I(info->used, dest, (i>>1)&7);
+ break;
+ case RSP_SQV:
+ case RSP_SRV:
+ // WARNING WARNING WARNING
+ // we assume this instruction always used to store the full vector
+ // i.e. the address is always 16 bytes aligned
+ for (i=0; i<8; i++)
+ RSP_SET_VEC_I(info->used, dest, i);
+ break;
+ case RSP_SPV:
+ case RSP_SUV:
+ case RSP_SHV:
+ case RSP_SWV:
+ for (i=0; i<8; i++)
+ RSP_SET_VEC_I(info->used, dest, i);
+ break;
+ case RSP_SFV:
+ for (i=(index>>1); i<(index>>1)+4; i++)
+ RSP_SET_VEC_I(info->used, dest, i);
+ break;
+ case RSP_STV:
+ {
+ // 31 25 20 15 10 6 0
+ // --------------------------------------------------
+ // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset |
+ // --------------------------------------------------
+ //
+ // Stores one element from maximum of 8 vectors, while incrementing element index
+
+ int element;
+ int vs = dest;
+ int ve = dest + 8;
+ if (ve > 32)
+ ve = 32;
+
+ element = 8 - (index >> 1);
+ if (index & 0x1)
+ log(M64MSG_ERROR, "RSP: STV: index = %d at %08X\n", index, rsp.ppc);
+
+ for (i=vs; i < ve; i++)
+ {
+ RSP_SET_VEC_I(info->used, i, element & 0x7);
+ element++;
+ }
+ break;
+ }
+
+ case RSP_VMULF:
+ case RSP_VMULU:
+ case RSP_VMUDL:
+ case RSP_VMUDM:
+ case RSP_VMUDN:
+ case RSP_VMUDH:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 14);
+ }
+ break;
+ }
+ case RSP_VMACF:
+ case RSP_VMACU:
+ case RSP_VMADL:
+ case RSP_VMADM:
+ case RSP_VMADN:
+ case RSP_VMADH:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->used, i, 14);
+ RSP_SET_ACCU_I(info->set, i, 14);
+ }
+ break;
+ }
+ case RSP_VADD:
+ case RSP_VSUB:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ RSP_SET_FLAG_I(info->used, 0);
+ RSP_SET_FLAG_I(info->set, 0);
+ break;
+ }
+ case RSP_VABS:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ break;
+ }
+ case RSP_VADDC:
+ case RSP_VSUBC:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ RSP_SET_FLAG_I(info->set, 0);
+ break;
+ }
+ case RSP_VSAW:
+ switch (EL)
+ {
+ case 0x08: // VSAWH
+ {
+ for (i=0; i < 8; i++)
+ {
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->used, i, 8);
+ }
+ break;
+ }
+ case 0x09: // VSAWM
+ {
+ for (i=0; i < 8; i++)
+ {
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->used, i, 4);
+ }
+ break;
+ }
+ case 0x0a: // VSAWL
+ {
+ for (i=0; i < 8; i++)
+ {
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->used, i, 2);
+ }
+ break;
+ }
+ default:
+ log(M64MSG_ERROR, "RSP: VSAW: el = %d\n", EL);
+ }
+ break;
+ case RSP_VLT:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ RSP_SET_FLAG_I(info->set, 0);
+ RSP_SET_FLAG_I(info->set, 1);
+ break;
+ }
+ case RSP_VEQ:
+ case RSP_VNE:
+ case RSP_VGE:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ RSP_SET_FLAG_I(info->used, 0);
+ RSP_SET_FLAG_I(info->set, 0);
+ RSP_SET_FLAG_I(info->set, 1);
+ break;
+ }
+ case RSP_VCL:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ RSP_SET_FLAG_I(info->used, 0);
+ RSP_SET_FLAG_I(info->used, 1);
+ RSP_SET_FLAG_I(info->set, 0);
+ RSP_SET_FLAG_I(info->set, 1);
+ RSP_SET_FLAG_I(info->set, 2);
+ break;
+ }
+ case RSP_VCH:
+ case RSP_VCR:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ RSP_SET_FLAG_I(info->set, 0);
+ RSP_SET_FLAG_I(info->set, 1);
+ RSP_SET_FLAG_I(info->set, 2);
+ break;
+ }
+ case RSP_VMRG:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ RSP_SET_FLAG_I(info->used, 1);
+ break;
+ }
+ case RSP_VAND:
+ case RSP_VNAND:
+ case RSP_VOR:
+ case RSP_VNOR:
+ case RSP_VXOR:
+ case RSP_VNXOR:
+ {
+ for (i=0; i < 8; i++)
+ {
+ int sel = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS1REG, i);
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+ RSP_SET_VEC_I(info->set, VDREG, i);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+ break;
+ }
+ case RSP_VRCP:
+ case RSP_VRCPL:
+ case RSP_VRCPH:
+ case RSP_VRSQL:
+ case RSP_VRSQH:
+ {
+ int del = (VS1REG & 7);
+ int sel = VEC_EL_2(EL, del);
+
+ RSP_SET_VEC_I(info->used, VS2REG, sel);
+
+ for (i=0; i < 8; i++)
+ {
+ int element = VEC_EL_2(EL, i);
+ RSP_SET_VEC_I(info->used, VS2REG, element);
+ RSP_SET_ACCU_I(info->set, i, 2);
+ }
+
+ RSP_SET_VEC_I(info->set, VDREG, del);
+ break;
+ }
+ case RSP_VMOV:
+ {
+ int element = VS1REG & 7;
+ RSP_SET_VEC_I(info->used, VS2REG, VEC_EL_2(EL, 7-element));
+ RSP_SET_VEC_I(info->set, VDREG, element);
+ break;
+ }
+
+ default:
+ {
+ // char string[200];
+ // rsp_dasm_one(string, 0x800, op);
+ // if (strcmp(string, "???")) {
+ // printf("%s\n", string);
+ // printf("unimplemented opcode\n");
+ // }
+ break;
+ }
+ }
+}
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#include "rsp.h"
+
+struct rsp_regmask_t {
+ //UINT32 r;
+ UINT8 v[32];
+ UINT32 accu;
+ UINT8 flag;
+};
+
+#define RSP_GET_REG_I(i, R) ( (i).r & (1<<(R)) )
+#define RSP_SET_REG_I(i, R) (i).r |= (1<<(R))
+#define RSP_CLEAR_REG_I(i, R) (i).r &= ~(1<<(R))
+
+#define RSP_GET_VEC_I(i, R, I) ( (i).v[R] & (1<<(I)) )
+#define RSP_SET_VEC_I(i, R, I) (i).v[R] |= (1<<(I))
+#define RSP_CLEAR_VEC_I(i, R, I) (i).v[R] &= ~(1<<(I))
+
+#define RSP_GET_ACCU_I(i, I, P) ( (i).accu & ((P)<<(I)*4) )
+#define RSP_SET_ACCU_I(i, I, P) (i).accu |= ((P)<<(I)*4)
+#define RSP_CLEAR_ACCU_I(i, I, P) (i).accu &= ~((P)<<(I)*4)
+
+#define RSP_GET_FLAG_I(i, R) ( (i).flag & (1<<(R)) )
+#define RSP_SET_FLAG_I(i, R) (i).flag |= (1<<(R))
+#define RSP_CLEAR_FLAG_I(i, R) (i).flag &= ~(1<<(R))
+
+#define RSP_OPINFO_JUMP 1
+#define RSP_OPINFO_BREAK 2
+#define RSP_OPINFO_COND 4
+#define RSP_OPINFO_LINK 8
+#define RSP_OPINFO_USEPC 16
+struct rsp_opinfo_t {
+ UINT32 op; // original opcode
+ int op2; // simplified opcode
+ rsp_regmask_t used;
+ rsp_regmask_t set;
+ int flags;
+};
+
+void rsp_get_opinfo(UINT32 op, rsp_opinfo_t * info);
+
+#define RSP_BASIC_OFFS 0x000
+#define RSP_SPECIAL_OFFS 0x040
+#define RSP_LWC2_OFFS 0x0a0
+#define RSP_SWC2_OFFS 0x0c0
+#define RSP_COP2_1_OFFS 0x080
+#define RSP_COP2_2_OFFS 0x100
+#define RSP_CONTROL_OFFS 0x140
+
+
+#define RSP_STOP (RSP_CONTROL_OFFS + 0x00)
+#define RSP_LOOP (RSP_CONTROL_OFFS + 0x01)
+#define RSP_JUMP (RSP_CONTROL_OFFS + 0x02)
+#define RSP_CONDJUMP (RSP_CONTROL_OFFS + 0x03)
+#define RSP_JUMPLOCAL (RSP_CONTROL_OFFS + 0x04)
+#define RSP_CONDJUMPLOCAL (RSP_CONTROL_OFFS + 0x05)
+
+
+#define RSP_SPECIAL (RSP_BASIC_OFFS + 0x00)
+#define RSP_REGIMM (RSP_BASIC_OFFS + 0x01)
+#define RSP_J (RSP_BASIC_OFFS + 0x02)
+#define RSP_JAL (RSP_BASIC_OFFS + 0x03)
+#define RSP_BEQ (RSP_BASIC_OFFS + 0x04)
+#define RSP_BNE (RSP_BASIC_OFFS + 0x05)
+#define RSP_BLEZ (RSP_BASIC_OFFS + 0x06)
+#define RSP_BGTZ (RSP_BASIC_OFFS + 0x07)
+#define RSP_ADDI (RSP_BASIC_OFFS + 0x08)
+#define RSP_ADDIU (RSP_BASIC_OFFS + 0x09)
+#define RSP_SLTI (RSP_BASIC_OFFS + 0x0a)
+#define RSP_SLTIU (RSP_BASIC_OFFS + 0x0b)
+#define RSP_ANDI (RSP_BASIC_OFFS + 0x0c)
+#define RSP_ORI (RSP_BASIC_OFFS + 0x0d)
+#define RSP_XORI (RSP_BASIC_OFFS + 0x0e)
+#define RSP_LUI (RSP_BASIC_OFFS + 0x0f)
+#define RSP_COP0 (RSP_BASIC_OFFS + 0x10)
+#define RSP_COP2 (RSP_BASIC_OFFS + 0x12)
+#define RSP_LB (RSP_BASIC_OFFS + 0x20)
+#define RSP_LH (RSP_BASIC_OFFS + 0x21)
+#define RSP_LW (RSP_BASIC_OFFS + 0x23)
+#define RSP_LBU (RSP_BASIC_OFFS + 0x24)
+#define RSP_LHU (RSP_BASIC_OFFS + 0x25)
+#define RSP_SB (RSP_BASIC_OFFS + 0x28)
+#define RSP_SH (RSP_BASIC_OFFS + 0x29)
+#define RSP_SW (RSP_BASIC_OFFS + 0x2b)
+#define RSP_LWC2 (RSP_BASIC_OFFS + 0x32)
+#define RSP_SWC2 (RSP_BASIC_OFFS + 0x3a)
+#define RSP_BLTZ (RSP_BASIC_OFFS + 0x3b)
+#define RSP_BGEZ (RSP_BASIC_OFFS + 0x3c)
+#define RSP_BGEZAL (RSP_BASIC_OFFS + 0x3d)
+
+#define RSP_SLL (RSP_SPECIAL_OFFS + 0x00)
+#define RSP_SRL (RSP_SPECIAL_OFFS + 0x02)
+#define RSP_SRA (RSP_SPECIAL_OFFS + 0x03)
+#define RSP_SLLV (RSP_SPECIAL_OFFS + 0x04)
+#define RSP_SRLV (RSP_SPECIAL_OFFS + 0x06)
+#define RSP_SRAV (RSP_SPECIAL_OFFS + 0x07)
+#define RSP_JR (RSP_SPECIAL_OFFS + 0x08)
+#define RSP_JALR (RSP_SPECIAL_OFFS + 0x09)
+#define RSP_BREAK (RSP_SPECIAL_OFFS + 0x0d)
+#define RSP_ADD (RSP_SPECIAL_OFFS + 0x20)
+#define RSP_ADDU (RSP_SPECIAL_OFFS + 0x21)
+#define RSP_SUB (RSP_SPECIAL_OFFS + 0x22)
+#define RSP_SUBU (RSP_SPECIAL_OFFS + 0x23)
+#define RSP_AND (RSP_SPECIAL_OFFS + 0x24)
+#define RSP_OR (RSP_SPECIAL_OFFS + 0x25)
+#define RSP_XOR (RSP_SPECIAL_OFFS + 0x26)
+#define RSP_NOR (RSP_SPECIAL_OFFS + 0x27)
+#define RSP_SLT (RSP_SPECIAL_OFFS + 0x2a)
+#define RSP_SLTU (RSP_SPECIAL_OFFS + 0x2b)
+
+#define RSP_MFC2 (RSP_COP2_1_OFFS + 0x00)
+#define RSP_CFC2 (RSP_COP2_1_OFFS + 0x02)
+#define RSP_MTC2 (RSP_COP2_1_OFFS + 0x04)
+#define RSP_CTC2 (RSP_COP2_1_OFFS + 0x06)
+
+
+#define RSP_LBV (RSP_LWC2_OFFS + 0x00)
+#define RSP_LSV (RSP_LWC2_OFFS + 0x01)
+#define RSP_LLV (RSP_LWC2_OFFS + 0x02)
+#define RSP_LDV (RSP_LWC2_OFFS + 0x03)
+#define RSP_LQV (RSP_LWC2_OFFS + 0x04)
+#define RSP_LRV (RSP_LWC2_OFFS + 0x05)
+#define RSP_LPV (RSP_LWC2_OFFS + 0x06)
+#define RSP_LUV (RSP_LWC2_OFFS + 0x07)
+#define RSP_LHV (RSP_LWC2_OFFS + 0x08)
+#define RSP_LFV (RSP_LWC2_OFFS + 0x09)
+#define RSP_LWV (RSP_LWC2_OFFS + 0x0a)
+#define RSP_LTV (RSP_LWC2_OFFS + 0x0b)
+
+#define RSP_SBV (RSP_SWC2_OFFS + 0x00)
+#define RSP_SSV (RSP_SWC2_OFFS + 0x01)
+#define RSP_SLV (RSP_SWC2_OFFS + 0x02)
+#define RSP_SDV (RSP_SWC2_OFFS + 0x03)
+#define RSP_SQV (RSP_SWC2_OFFS + 0x04)
+#define RSP_SRV (RSP_SWC2_OFFS + 0x05)
+#define RSP_SPV (RSP_SWC2_OFFS + 0x06)
+#define RSP_SUV (RSP_SWC2_OFFS + 0x07)
+#define RSP_SHV (RSP_SWC2_OFFS + 0x08)
+#define RSP_SFV (RSP_SWC2_OFFS + 0x09)
+#define RSP_SWV (RSP_SWC2_OFFS + 0x0a)
+#define RSP_STV (RSP_SWC2_OFFS + 0x0b)
+
+#define RSP_VMULF (RSP_COP2_2_OFFS + 0x00)
+#define RSP_VMULU (RSP_COP2_2_OFFS + 0x01)
+#define RSP_VMUDL (RSP_COP2_2_OFFS + 0x04)
+#define RSP_VMUDM (RSP_COP2_2_OFFS + 0x05)
+#define RSP_VMUDN (RSP_COP2_2_OFFS + 0x06)
+#define RSP_VMUDH (RSP_COP2_2_OFFS + 0x07)
+#define RSP_VMACF (RSP_COP2_2_OFFS + 0x08)
+#define RSP_VMACU (RSP_COP2_2_OFFS + 0x09)
+#define RSP_VMADL (RSP_COP2_2_OFFS + 0x0c)
+#define RSP_VMADM (RSP_COP2_2_OFFS + 0x0d)
+#define RSP_VMADN (RSP_COP2_2_OFFS + 0x0e)
+#define RSP_VMADH (RSP_COP2_2_OFFS + 0x0f)
+#define RSP_VADD (RSP_COP2_2_OFFS + 0x10)
+#define RSP_VSUB (RSP_COP2_2_OFFS + 0x11)
+#define RSP_VABS (RSP_COP2_2_OFFS + 0x13)
+#define RSP_VADDC (RSP_COP2_2_OFFS + 0x14)
+#define RSP_VSUBC (RSP_COP2_2_OFFS + 0x15)
+#define RSP_VSAW (RSP_COP2_2_OFFS + 0x1d)
+#define RSP_VLT (RSP_COP2_2_OFFS + 0x20)
+#define RSP_VEQ (RSP_COP2_2_OFFS + 0x21)
+#define RSP_VNE (RSP_COP2_2_OFFS + 0x22)
+#define RSP_VGE (RSP_COP2_2_OFFS + 0x23)
+#define RSP_VCL (RSP_COP2_2_OFFS + 0x24)
+#define RSP_VCH (RSP_COP2_2_OFFS + 0x25)
+#define RSP_VCR (RSP_COP2_2_OFFS + 0x26)
+#define RSP_VMRG (RSP_COP2_2_OFFS + 0x27)
+#define RSP_VAND (RSP_COP2_2_OFFS + 0x28)
+#define RSP_VNAND (RSP_COP2_2_OFFS + 0x29)
+#define RSP_VOR (RSP_COP2_2_OFFS + 0x2a)
+#define RSP_VNOR (RSP_COP2_2_OFFS + 0x2b)
+#define RSP_VXOR (RSP_COP2_2_OFFS + 0x2c)
+#define RSP_VNXOR (RSP_COP2_2_OFFS + 0x2d)
+#define RSP_VRCP (RSP_COP2_2_OFFS + 0x30)
+#define RSP_VRCPL (RSP_COP2_2_OFFS + 0x31)
+#define RSP_VRCPH (RSP_COP2_2_OFFS + 0x32)
+#define RSP_VMOV (RSP_COP2_2_OFFS + 0x33)
+#define RSP_VRSQL (RSP_COP2_2_OFFS + 0x35)
+#define RSP_VRSQH (RSP_COP2_2_OFFS + 0x36)
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#include "rsp_recomp.h"
+#include <assert.h>
+
+#define GENDEBUG
+
+struct gen_t {
+ UINT32 crc;
+ int lbc;
+ rsp_bc_t * bc;
+#ifdef GENDEBUG
+ char name[32];
+#endif
+};
+
+struct opinfo_t {
+ int visit, labeled;
+ int label;
+
+ unsigned int nbgen;
+ unsigned int szgen;
+ gen_t * gentable;
+ gen_t * curgen;
+};
+
+struct branch_t {
+ int start, end;
+};
+
+static int curvisit;
+static opinfo_t opinfo[0x1000/4];
+static int jumps[0x1000];
+static unsigned int nb_branches;
+static branch_t branches[256];
+static unsigned int nb_labels;
+static int labels[256];
+
+#define OPI(pc) opinfo[(pc)>>2]
+/*inline*/ void SETLABEL(int pc) {
+ //printf("%x\n", pc);
+ //pc &= 0xfff;
+ assert(pc >= 0 && pc < 0x1000);
+ if (OPI(pc).labeled != curvisit) {
+ labels[nb_labels] = pc;
+ OPI(pc).label = nb_labels++;
+ assert(nb_labels < sizeof(labels)/sizeof(labels[0]));
+ OPI(pc).labeled = curvisit;
+ }
+}
+
+#define ABS(addr) (((addr) << 2) & 0xfff)
+#define REL(offset) ((pc + ((offset) << 2)) & 0xfff)
+
+static UINT32 prep_gen(int pc, UINT32 crc, int & len)
+{
+ UINT32 op;
+ int br = 0;
+
+ branches[nb_branches].start = pc;
+
+ while ( !br )
+ {
+ if (OPI(pc).visit == curvisit) {
+ SETLABEL((pc)&0xfff);
+ SETLABEL((pc+4)&0xfff);
+ break;
+ }
+
+ OPI(pc).visit = curvisit;
+
+ op = ROPCODE(pc);
+ crc = ((crc<<1)|(crc>>31))^op^pc;
+ pc = (pc+4)&0xfff;
+ len++;
+
+ switch (op >> 26)
+ {
+ case 0x00: /* SPECIAL */
+ {
+ switch (op & 0x3f)
+ {
+ case 0x08: /* JR */
+ br = 1;
+ break;
+ case 0x09: /* JALR */
+ //br = 1;
+ break;
+ case 0x0d: /* BREAK */
+ br = 1;
+ break;
+ }
+ break;
+ }
+
+ case 0x01: /* REGIMM */
+ {
+ switch (RTREG)
+ {
+ case 0x00: /* BLTZ */
+ case 0x01: /* BGEZ */
+ SETLABEL(REL(SIMM16));
+ break;
+ case 0x11: /* BGEZAL */
+ //br = 1;
+ break;
+ }
+ break;
+ }
+
+ case 0x02: /* J */
+ SETLABEL(ABS(UIMM26));
+ br = 1;
+ break;
+ case 0x04: /* BEQ */
+ case 0x05: /* BNE */
+ case 0x06: /* BLEZ */
+ case 0x07: /* BGTZ */
+ SETLABEL(REL(SIMM16));
+ break;
+ case 0x03: /* JAL */
+ //SETLABEL(ABS(UIMM26));
+ //br = 1;
+ break;
+ }
+
+ }
+
+ branches[nb_branches++].end = pc;
+ assert(nb_branches < sizeof(branches)/sizeof(branches[0]));
+
+ return crc;
+}
+
+static void rsp_gen(int pc)
+{
+ unsigned int i;
+
+ curvisit++;
+ if (!curvisit) {
+ // we looped, reset all visit counters
+ for (i=0; i<0x1000/4; i++) {
+ opinfo[i].visit = 0;
+ opinfo[i].labeled = 0;
+ }
+ curvisit++;
+ }
+
+ nb_branches = 0;
+ nb_labels = 0;
+
+ int len = 0;
+ UINT32 crc = prep_gen(pc, 0, len);
+
+ for (i=0; i<nb_labels; i++) {
+ if (OPI(labels[i]).visit != curvisit)
+ crc = prep_gen(labels[i], crc, len);
+ }
+
+ opinfo_t * opi = &OPI(pc);
+ if (opi->gentable) {
+ for (i=0; i<opi->nbgen; i++)
+ if (opi->gentable[i].crc == crc) {
+ opi->curgen = opi->gentable + i;
+ return;
+ }
+ }
+ if (opi->nbgen >= opi->szgen) {
+ if (opi->szgen)
+ opi->szgen *= 2;
+ else
+ opi->szgen = 4;
+ opi->gentable = (gen_t *) realloc(opi->gentable, sizeof(gen_t)*(opi->szgen));
+ }
+ gen_t * gen;
+ gen = opi->gentable + opi->nbgen++;
+ gen->crc = crc;
+ opi->curgen = gen;
+
+ // convert to bytecode
+ unsigned int lbc = 0;
+ static rsp_bc_t bc[0x1000*2+10];
+ for (i=0; i<nb_branches; i++) {
+ int pc;
+ int loopc;
+ int cont = 1;
+ rsp_opinfo_t delayed;
+ delayed.op = 0;
+ for (pc = branches[i].start; cont || delayed.op; pc = (pc+4)&0xfff) {
+ UINT32 op = ROPCODE(pc);
+
+ // int realpc = pc;
+ // char s[128];
+ // rsp_dasm_one(s, realpc, op);
+ // printf("%d %3x\t%s\n", lbc, realpc, s);
+
+ rsp_opinfo_t info;
+ rsp_get_opinfo(op, &info);
+ if ((info.flags & RSP_OPINFO_JUMP) && !cont)
+ info.flags = 0;
+ else {
+ int nop = 0;
+ switch (info.op2) {
+ case RSP_SLL:
+ case RSP_SRL:
+ case RSP_SRA:
+ if (RDREG == RTREG && SHIFT == 0)
+ nop = 1;
+ break;
+ }
+ if (cont)
+ jumps[pc] = lbc;
+ if (!nop) {
+ bc[lbc].op = op;
+ bc[lbc].op2 = info.op2;
+ bc[lbc].flags = info.flags | (((pc&0xffc)<<5)-2) | (!cont? (1<<15):0);
+ lbc++;
+ }
+ loopc = (pc+4)&0xfff;
+ }
+ if (delayed.op) {
+ int addop = 0;
+ const UINT32 op = delayed.op;
+ switch (delayed.op2) {
+ case RSP_BLTZ:
+ case RSP_BGEZ:
+ case RSP_BEQ:
+ case RSP_BNE:
+ case RSP_BLEZ:
+ case RSP_BGTZ:
+ addop = RSP_CONDJUMPLOCAL;
+ bc[lbc].flags = (pc + (SIMM16<<2))&0xfff; // address to be resolved later
+ break;
+ case RSP_J:
+ addop = RSP_JUMPLOCAL;
+ bc[lbc].flags = (UIMM26<<2)&0xfff; // address to be resolved later
+ break;
+ case RSP_BGEZAL:
+ addop = RSP_CONDJUMP;
+ break;
+ case RSP_JAL:
+ case RSP_JR:
+ case RSP_JALR:
+ addop = RSP_JUMP;
+ break;
+ }
+ bc[lbc].op = delayed.op;
+ bc[lbc].op2 = addop;
+ lbc++;
+ }
+ if (info.flags & RSP_OPINFO_JUMP) {
+ delayed = info;
+ } else
+ delayed.op = 0;
+ if (((pc + 4)&0xfff) == branches[i].end)
+ cont = 0;
+ }
+ if (bc[lbc-1].op2 != RSP_JUMP &&
+ bc[lbc-1].op2 != RSP_JUMPLOCAL &&
+ bc[lbc-1].op2 != RSP_BREAK &&
+ bc[lbc-1].op2 != RSP_STOP) {
+
+ bc[lbc].op = 0;
+ bc[lbc].op2 = RSP_LOOP;
+ bc[lbc].flags = loopc; // address to be resolved later
+ lbc++;
+ }
+ }
+
+ // resolve local jumps
+ for (i=0; i<lbc; i++) {
+ // printf("%d %x\n", i, bc[i].op2);
+ // if (bc[i].op2 < RSP_CONTROL_OFFS) {
+ // int realpc = (bc[i].flags>>3)&0xffc;
+ // char s[128];
+ // rsp_dasm_one(s, realpc, bc[i].op);
+ // printf("%3x\t%s\n", realpc, s);
+ // }
+ switch (bc[i].op2) {
+ case RSP_JUMPLOCAL:
+ case RSP_CONDJUMPLOCAL:
+ case RSP_LOOP:
+ {
+ // int pc;
+ // for (pc = 0; pc<lbc; pc++)
+ // if (bc[pc].op2 < RSP_CONTROL_OFFS &&
+ // !(bc[pc].flags & (1<<15)) &&
+ // ((bc[pc].flags>>5)<<2) == bc[i].flags)
+ // break;
+ // assert(pc < lbc);
+ // bc[i].flags = pc<<5;
+ bc[i].flags = jumps[bc[i].flags]<<5;
+ break;
+ }
+ }
+ }
+
+ gen->lbc = lbc;
+ gen->bc = (rsp_bc_t *) malloc(sizeof(rsp_bc_t)*lbc);
+ memcpy(gen->bc, bc, sizeof(rsp_bc_t)*lbc);
+}
+
+void rsp_invalidate(int begin, int len)
+{
+ //printf("invalidate %x %x\n", begin, len);
+ begin = 0; len = 0x1000;
+ assert(begin+len<=0x1000);
+ while (len > 0) {
+ OPI(begin).curgen = 0;
+ begin += 4;
+ len -= 4;
+ }
+ rsp.inval_gen = 1;
+}
+
+inline void rsp_execute_one(RSP_REGS & rsp, const UINT32 op)
+{
+ switch (op >> 26)
+ {
+ case 0x12: /* COP2 */
+ {
+ handle_vector_ops(op);
+ break;
+ }
+
+ case 0x32: /* LWC2 */ handle_lwc2(op); break;
+ case 0x3a: /* SWC2 */ handle_swc2(op); break;
+
+ default:
+ {
+ unimplemented_opcode(op);
+ break;
+ }
+ }
+}
+
+static int cond;
+static int run(RSP_REGS & rsp, gen_t * gen)
+{
+ int pc = 0;
+
+ cond = 0;
+ for ( ; ; ) {
+ const rsp_bc_t & bc = gen->bc[pc];
+ const UINT32 op = bc.op;
+ const int op2 = bc.op2;
+
+ // if (op2 < RSP_CONTROL_OFFS) {
+ // int realpc = (bc.flags>>3)&0xffc;
+ // char s[128];
+ // rsp_dasm_one(s, realpc, op);
+ // fprintf(stderr, "%3x\t%s\n", realpc, s);
+ // }
+
+ pc++;
+ switch (op2) {
+ case RSP_LOOP:
+ pc = bc.flags>>5;
+ break;
+ case RSP_JUMPLOCAL:
+ case RSP_CONDJUMPLOCAL:
+ if (cond) {
+ pc = bc.flags>>5;
+ cond = 0;
+ }
+ break;
+ case RSP_JUMP:
+ case RSP_CONDJUMP:
+ if (cond) {
+ return 0;
+ }
+ break;
+
+ #define _LINK(l) rsp.r[l] = ((bc.flags >>3)+8)&0xffc
+ #define _JUMP_PC(a) { cond=1; rsp.nextpc = ((a) & 0xfff); }
+ #define _JUMP_PC_L(a, l) { _LINK(l); _JUMP_PC(a); }
+ #define _JUMP_REL(a) _JUMP_PC(((bc.flags >>3)+4+(a<<2))&0xffc)
+ #define _JUMP_REL_L(a, l) _JUMP_PC_L(((bc.flags >>3)+4+(a<<2))&0xffc, l)
+
+ case RSP_SLL: if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break;
+ case RSP_SRL: if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break;
+ case RSP_SRA: if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break;
+ case RSP_SLLV: if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break;
+ case RSP_SRLV: if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break;
+ case RSP_SRAV: if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break;
+ case RSP_JR: _JUMP_PC(RSVAL); break;
+ case RSP_JALR: _JUMP_PC_L(RSVAL, RDREG); break;
+ case RSP_BREAK:
+ {
+ *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE );
+ if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) {
+ *z64_rspinfo.MI_INTR_REG |= 1;
+ z64_rspinfo.CheckInterrupts();
+ }
+ return 1;
+ }
+ case RSP_ADD: if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
+ case RSP_ADDU: if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break;
+ case RSP_SUB: if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
+ case RSP_SUBU: if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break;
+ case RSP_AND: if (RDREG) RDVAL = RSVAL & RTVAL; break;
+ case RSP_OR: if (RDREG) RDVAL = RSVAL | RTVAL; break;
+ case RSP_XOR: if (RDREG) RDVAL = RSVAL ^ RTVAL; break;
+ case RSP_NOR: if (RDREG) RDVAL = ~(RSVAL | RTVAL); break;
+ case RSP_SLT: if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break;
+ case RSP_SLTU: if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break;
+ case RSP_BLTZ: if ((INT32)(RSVAL) < 0) cond = 1; break;
+ case RSP_BGEZ: if ((INT32)(RSVAL) >= 0) cond = 1; break;
+ case RSP_BGEZAL: _LINK(31); if ((INT32)(RSVAL) >= 0) _JUMP_REL(SIMM16); break;
+ case RSP_J: cond = 1; break;
+ case RSP_JAL: _JUMP_PC_L(UIMM26<<2, 31); break;
+ case RSP_BEQ: if (RSVAL == RTVAL) cond = 1; break;
+ case RSP_BNE: if (RSVAL != RTVAL) cond = 1; break;
+ case RSP_BLEZ: if ((INT32)RSVAL <= 0) cond = 1; break;
+ case RSP_BGTZ: if ((INT32)RSVAL > 0) cond = 1; break;
+ case RSP_ADDI: if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
+ case RSP_ADDIU: if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break;
+ case RSP_SLTI: if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break;
+ case RSP_SLTIU: if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break;
+ case RSP_ANDI: if (RTREG) RTVAL = RSVAL & UIMM16; break;
+ case RSP_ORI: if (RTREG) RTVAL = RSVAL | UIMM16; break;
+ case RSP_XORI: if (RTREG) RTVAL = RSVAL ^ UIMM16; break;
+ case RSP_LUI: if (RTREG) RTVAL = UIMM16 << 16; break;
+
+ case RSP_COP0:
+ {
+ switch ((op >> 21) & 0x1f)
+ {
+ case 0x00: /* MFC0 */
+ if (RTREG)
+ RTVAL = get_cop0_reg(RDREG);
+ break;
+ case 0x04: /* MTC0 */
+ set_cop0_reg(RDREG, RTVAL);
+ if (rsp.inval_gen) {
+ rsp.inval_gen = 0;
+ sp_pc = ((bc.flags >>3) + 4)&0xffc;
+ return 2;
+ }
+ break;
+ default:
+ log(M64MSG_WARNING, "unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op);
+ break;
+ }
+ break;
+ }
+
+ case RSP_MFC2:
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+
+ int el = (op >> 7) & 0xf;
+ UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf);
+ UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf);
+ if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2));
+ break;
+ }
+ case RSP_CFC2:
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ // VP to sign extend or to not sign extend ?
+ //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG];
+ if (RTREG) RTVAL = rsp.flag[RDREG];
+ break;
+ }
+ case RSP_MTC2:
+ {
+ // 31 25 20 15 10 6 0
+ // ---------------------------------------------------
+ // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 |
+ // ---------------------------------------------------
+ //
+
+ int el = (op >> 7) & 0xf;
+ VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff;
+ VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff;
+ break;
+ }
+ case RSP_CTC2:
+ {
+ // 31 25 20 15 10 0
+ // ------------------------------------------------
+ // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 |
+ // ------------------------------------------------
+ //
+
+ rsp.flag[RDREG] = RTVAL & 0xffff;
+ break;
+ }
+ case RSP_LB: if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break;
+ case RSP_LH: if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break;
+ case RSP_LW: if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break;
+ case RSP_LBU: if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break;
+ case RSP_LHU: if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break;
+ case RSP_SB: WRITE8(RSVAL + SIMM16, RTVAL); break;
+ case RSP_SH: WRITE16(RSVAL + SIMM16, RTVAL); break;
+ case RSP_SW: WRITE32(RSVAL + SIMM16, RTVAL); break;
+
+ default:
+ switch (op >> 26)
+ {
+ case 0x12: /* COP2 */
+ handle_vector_ops(op);
+ break;
+ case 0x32: /* LWC2 */
+ handle_lwc2(op);
+ break;
+ case 0x3a: /* SWC2 */
+ handle_swc2(op);
+ break;
+ }
+ }
+ }
+}
+
+int rsp_gen_cache_hit;
+int rsp_gen_cache_miss;
+int rsp_jump(int pc)
+{
+ pc &= 0xfff;
+ sp_pc = pc;
+ rsp.nextpc = ~0;
+ opinfo_t * opi = &OPI(pc);
+ gen_t * gen = opi->curgen;
+ rsp_gen_cache_hit++;
+ if (!gen) {
+ rsp_gen_cache_miss++;
+ rsp_gen(pc);
+ }
+ gen = opi->curgen;
+ //fprintf(stderr, "rsp_jump %x (%s)\n", pc, gen->name);
+
+ int res = run(rsp, gen);
+
+ //fprintf(stderr, "r31 %x from %x nextpc %x pc %x res %d (%s)\n", rsp.r[31], pc, rsp.nextpc, sp_pc, res, gen->name);
+ if (rsp.nextpc != ~0U)
+ {
+ sp_pc = (rsp.nextpc & 0xfff);
+ rsp.nextpc = ~0U;
+ }
+ else
+ {
+ //sp_pc = ((sp_pc+4)&0xfff);
+ }
+ return res;
+}
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#include "rsp_opinfo.h"
+
+struct rsp_bc_t {
+ UINT32 op; // original opcode
+ short op2; // simplified opcode
+ short flags;
+ rsp_regmask_t need;
+};
--- /dev/null
+/*
+ * z64
+ *
+ * Copyright (C) 2007 ziggy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+**/
+
+#ifndef _Z64_H_
+#define _Z64_H_
+#include <stdint.h>
+
+#define DACRATE_NTSC (48681812)
+#define DACRATE_PAL (49656530)
+#define DACRATE_MPAL (48628316)
+
+#define SP_INTERRUPT 0x1
+#define SI_INTERRUPT 0x2
+#define AI_INTERRUPT 0x4
+#define VI_INTERRUPT 0x8
+#define PI_INTERRUPT 0x10
+#define DP_INTERRUPT 0x20
+
+#define SP_STATUS_HALT 0x0001
+#define SP_STATUS_BROKE 0x0002
+#define SP_STATUS_DMABUSY 0x0004
+#define SP_STATUS_DMAFULL 0x0008
+#define SP_STATUS_IOFULL 0x0010
+#define SP_STATUS_SSTEP 0x0020
+#define SP_STATUS_INTR_BREAK 0x0040
+#define SP_STATUS_SIGNAL0 0x0080
+#define SP_STATUS_SIGNAL1 0x0100
+#define SP_STATUS_SIGNAL2 0x0200
+#define SP_STATUS_SIGNAL3 0x0400
+#define SP_STATUS_SIGNAL4 0x0800
+#define SP_STATUS_SIGNAL5 0x1000
+#define SP_STATUS_SIGNAL6 0x2000
+#define SP_STATUS_SIGNAL7 0x4000
+
+#define DP_STATUS_XBUS_DMA 0x01
+#define DP_STATUS_FREEZE 0x02
+#define DP_STATUS_FLUSH 0x04
+#define DP_STATUS_START_GCLK 0x008
+#define DP_STATUS_TMEM_BUSY 0x010
+#define DP_STATUS_PIPE_BUSY 0x020
+#define DP_STATUS_CMD_BUSY 0x040
+#define DP_STATUS_CBUF_READY 0x080
+#define DP_STATUS_DMA_BUSY 0x100
+#define DP_STATUS_END_VALID 0x200
+#define DP_STATUS_START_VALID 0x400
+
+#define R4300i_SP_Intr 1
+
+
+#define LSB_FIRST 1 // TODO : check for platform
+#ifdef LSB_FIRST
+ #define BYTE_ADDR_XOR 3
+ #define WORD_ADDR_XOR 1
+ #define BYTE4_XOR_BE(a) ((a) ^ 3) /* read/write a byte to a 32-bit space */
+#else
+ #define BYTE_ADDR_XOR 0
+ #define WORD_ADDR_XOR 0
+ #define BYTE4_XOR_BE(a) (a)
+#endif
+
+
+typedef uint64_t UINT64;
+typedef int64_t INT64;
+typedef uint32_t UINT32;
+typedef int32_t INT32;
+typedef uint16_t UINT16;
+typedef int16_t INT16;
+typedef uint8_t UINT8;
+typedef int8_t INT8;
+typedef unsigned int offs_t;
+#endif
+