├── .gitignore ├── src ├── rsp_api_export.ver ├── rsp_recomp.h ├── osal_dynamiclib.h ├── osal_dynamiclib_unix.c ├── z64.h ├── osal_dynamiclib_win32.c ├── rsp_opinfo.h ├── main_rsp.cpp ├── rsp_gen.h ├── rsp.h ├── rsp_opinfo.cpp ├── rsp_recomp.cpp ├── rsp_dasm.cpp └── rsp_gen.cpp ├── .gitattributes ├── .travis.yml ├── .github └── workflows │ ├── schedule.yml │ └── build.yml ├── projects └── unix │ └── Makefile └── COPYING /.gitignore: -------------------------------------------------------------------------------- 1 | /projects/unix/_obj*/ 2 | /projects/unix/mupen64plus-rsp-z64*.so 3 | -------------------------------------------------------------------------------- /src/rsp_api_export.ver: -------------------------------------------------------------------------------- 1 | { global: 2 | PluginStartup; 3 | PluginShutdown; 4 | PluginGetVersion; 5 | DoRspCycles; 6 | InitiateRSP; 7 | RomClosed; 8 | local: *; }; 9 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | # normal text files 4 | *.6 text 5 | AUTHORS text 6 | *.c text 7 | *.cfg text 8 | *.cht text 9 | *.conf text 10 | COPYING text 11 | *.cpp text 12 | *.def text 13 | *-license text 14 | *.h text 15 | *.html text 16 | *.ini text 17 | INSTALL text 18 | LICENSES text 19 | Makefile text 20 | *.py text 21 | README text 22 | RELEASE text 23 | *.S text 24 | *.sh text 25 | *.txt text 26 | *.ver text 27 | 28 | # windows specific text files 29 | *.sln text eol=crlf 30 | *.vcproj text eol=crlf 31 | *.vcxproj text eol=crlf 32 | *.vcxproj.filters text eol=crlf 33 | 34 | # binary files 35 | *.gz binary 36 | *.ttf binary 37 | cursor.tex binary 38 | font.tex binary 39 | -------------------------------------------------------------------------------- /src/rsp_recomp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #include "rsp_opinfo.h" 23 | #include "z64.h" 24 | 25 | struct rsp_bc_t { 26 | UINT32 op; // original opcode 27 | short op2; // simplified opcode 28 | short flags; 29 | rsp_regmask_t need; 30 | }; 31 | -------------------------------------------------------------------------------- /src/osal_dynamiclib.h: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Mupen64plus-core - osal/dynamiclib.h * 3 | * Mupen64Plus homepage: https://mupen64plus.org/ * 4 | * Copyright (C) 2009 Richard Goedeken * 5 | * * 6 | * This program is free software; you can redistribute it and/or modify * 7 | * it under the terms of the GNU General Public License as published by * 8 | * the Free Software Foundation; either version 2 of the License, or * 9 | * (at your option) any later version. * 10 | * * 11 | * This program is distributed in the hope that it will be useful, * 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 | * GNU General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU General Public License * 17 | * along with this program; if not, write to the * 18 | * Free Software Foundation, Inc., * 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 20 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 21 | 22 | #if !defined(OSAL_DYNAMICLIB_H) 23 | #define OSAL_DYNAMICLIB_H 24 | 25 | #include "m64p_types.h" 26 | 27 | #ifdef __cplusplus 28 | extern "C" { 29 | #endif 30 | void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName); 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #endif /* #define OSAL_DYNAMICLIB_H */ 36 | 37 | -------------------------------------------------------------------------------- /src/osal_dynamiclib_unix.c: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Mupen64plus-core - osal/dynamiclib_unix.c * 3 | * Mupen64Plus homepage: https://mupen64plus.org/ * 4 | * Copyright (C) 2009 Richard Goedeken * 5 | * * 6 | * This program is free software; you can redistribute it and/or modify * 7 | * it under the terms of the GNU General Public License as published by * 8 | * the Free Software Foundation; either version 2 of the License, or * 9 | * (at your option) any later version. * 10 | * * 11 | * This program is distributed in the hope that it will be useful, * 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 | * GNU General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU General Public License * 17 | * along with this program; if not, write to the * 18 | * Free Software Foundation, Inc., * 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 20 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "m64p_types.h" 27 | #include "osal_dynamiclib.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) 33 | { 34 | if (pccProcedureName == NULL) 35 | return NULL; 36 | 37 | return dlsym(LibHandle, pccProcedureName); 38 | } 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | 44 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: cpp 4 | compiler: 5 | - gcc 6 | - clang 7 | addons: 8 | apt: 9 | packages: 10 | - git 11 | before_install: 12 | - git clone --depth=1 --branch=master git://github.com/mupen64plus/mupen64plus-core.git deps/mupen64plus-core 13 | env: 14 | - HLEVIDEO=0 15 | - HLEVIDEO=1 16 | script: 17 | - make -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 clean && LDFLAGS="-Wl,--no-add-needed -Wl,--no-undefined" OPTFLAGS="-O2" make CC="${CC}" CXX="${CXX}" -j$(nproc) -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 all 18 | 19 | # extra mxe build entries 20 | matrix: 21 | include: 22 | - env: 23 | - MXE_CPU=i686 24 | - PATH="/usr/lib/mxe/usr/bin/:$PATH" 25 | addons: 26 | apt: 27 | sources: 28 | - sourceline: 'deb http://pkg.mxe.cc/repos/apt/debian jessie main' 29 | key_url: 'http://pkg.mxe.cc/repos/apt/conf/mxeapt.gpg' 30 | packages: 31 | - mxe-i686-w64-mingw32.shared-gcc 32 | before_install: 33 | - git clone --depth=1 --branch=master git://github.com/mupen64plus/mupen64plus-core.git deps/mupen64plus-core 34 | script: 35 | - make UNAME=MINGW CROSS_COMPILE="${MXE_CPU}-w64-mingw32.shared-" CC="${MXE_CPU}-w64-mingw32.shared-gcc" CXX="${MXE_CPU}-w64-mingw32.shared-g++" HOST_CPU="${MXE_CPU}" -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 clean && 36 | make UNAME=MINGW CROSS_COMPILE="${MXE_CPU}-w64-mingw32.shared-" CC="${MXE_CPU}-w64-mingw32.shared-gcc" CXX="${MXE_CPU}-w64-mingw32.shared-g++" HOST_CPU="${MXE_CPU}" -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 -j$(nproc) all 37 | 38 | - env: 39 | - MXE_CPU=x86_64 40 | - PATH="/usr/lib/mxe/usr/bin/:$PATH" 41 | addons: 42 | apt: 43 | sources: 44 | - sourceline: 'deb http://pkg.mxe.cc/repos/apt/debian jessie main' 45 | key_url: 'http://pkg.mxe.cc/repos/apt/conf/mxeapt.gpg' 46 | packages: 47 | - mxe-x86-64-w64-mingw32.shared-gcc 48 | before_install: 49 | - git clone --depth=1 --branch=master git://github.com/mupen64plus/mupen64plus-core.git deps/mupen64plus-core 50 | script: 51 | - make UNAME=MINGW CROSS_COMPILE="${MXE_CPU}-w64-mingw32.shared-" CC="${MXE_CPU}-w64-mingw32.shared-gcc" CXX="${MXE_CPU}-w64-mingw32.shared-g++" HOST_CPU="${MXE_CPU}" -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 clean && 52 | make UNAME=MINGW CROSS_COMPILE="${MXE_CPU}-w64-mingw32.shared-" CC="${MXE_CPU}-w64-mingw32.shared-gcc" CXX="${MXE_CPU}-w64-mingw32.shared-g++" HOST_CPU="${MXE_CPU}" -C projects/unix APIDIR="$(pwd)/deps/mupen64plus-core/src/api/" V=1 -j$(nproc) all 53 | -------------------------------------------------------------------------------- /src/z64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #ifndef _Z64_H_ 23 | #define _Z64_H_ 24 | #include 25 | 26 | #define DACRATE_NTSC (48681812) 27 | #define DACRATE_PAL (49656530) 28 | #define DACRATE_MPAL (48628316) 29 | 30 | #define SP_INTERRUPT 0x1 31 | #define SI_INTERRUPT 0x2 32 | #define AI_INTERRUPT 0x4 33 | #define VI_INTERRUPT 0x8 34 | #define PI_INTERRUPT 0x10 35 | #define DP_INTERRUPT 0x20 36 | 37 | #define SP_STATUS_HALT 0x0001 38 | #define SP_STATUS_BROKE 0x0002 39 | #define SP_STATUS_DMABUSY 0x0004 40 | #define SP_STATUS_DMAFULL 0x0008 41 | #define SP_STATUS_IOFULL 0x0010 42 | #define SP_STATUS_SSTEP 0x0020 43 | #define SP_STATUS_INTR_BREAK 0x0040 44 | #define SP_STATUS_SIGNAL0 0x0080 45 | #define SP_STATUS_SIGNAL1 0x0100 46 | #define SP_STATUS_SIGNAL2 0x0200 47 | #define SP_STATUS_SIGNAL3 0x0400 48 | #define SP_STATUS_SIGNAL4 0x0800 49 | #define SP_STATUS_SIGNAL5 0x1000 50 | #define SP_STATUS_SIGNAL6 0x2000 51 | #define SP_STATUS_SIGNAL7 0x4000 52 | 53 | #define DP_STATUS_XBUS_DMA 0x01 54 | #define DP_STATUS_FREEZE 0x02 55 | #define DP_STATUS_FLUSH 0x04 56 | #define DP_STATUS_START_GCLK 0x008 57 | #define DP_STATUS_TMEM_BUSY 0x010 58 | #define DP_STATUS_PIPE_BUSY 0x020 59 | #define DP_STATUS_CMD_BUSY 0x040 60 | #define DP_STATUS_CBUF_READY 0x080 61 | #define DP_STATUS_DMA_BUSY 0x100 62 | #define DP_STATUS_END_VALID 0x200 63 | #define DP_STATUS_START_VALID 0x400 64 | 65 | #define R4300i_SP_Intr 1 66 | 67 | 68 | #define LSB_FIRST 1 // TODO : check for platform 69 | #ifdef LSB_FIRST 70 | #define BYTE_ADDR_XOR 3 71 | #define WORD_ADDR_XOR 1 72 | #define BYTE4_XOR_BE(a) ((a) ^ 3) /* read/write a byte to a 32-bit space */ 73 | #else 74 | #define BYTE_ADDR_XOR 0 75 | #define WORD_ADDR_XOR 0 76 | #define BYTE4_XOR_BE(a) (a) 77 | #endif 78 | 79 | 80 | typedef uint64_t UINT64; 81 | typedef int64_t INT64; 82 | typedef uint32_t UINT32; 83 | typedef int32_t INT32; 84 | typedef uint16_t UINT16; 85 | typedef int16_t INT16; 86 | typedef uint8_t UINT8; 87 | typedef int8_t INT8; 88 | typedef unsigned int offs_t; 89 | #endif 90 | 91 | -------------------------------------------------------------------------------- /src/osal_dynamiclib_win32.c: -------------------------------------------------------------------------------- 1 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | * Mupen64plus-ui-console - osal_dynamiclib_win32.c * 3 | * Mupen64Plus homepage: https://mupen64plus.org/ * 4 | * Copyright (C) 2009 Richard Goedeken * 5 | * * 6 | * This program is free software; you can redistribute it and/or modify * 7 | * it under the terms of the GNU General Public License as published by * 8 | * the Free Software Foundation; either version 2 of the License, or * 9 | * (at your option) any later version. * 10 | * * 11 | * This program is distributed in the hope that it will be useful, * 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 14 | * GNU General Public License for more details. * 15 | * * 16 | * You should have received a copy of the GNU General Public License * 17 | * along with this program; if not, write to the * 18 | * Free Software Foundation, Inc., * 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 20 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "m64p_types.h" 27 | #include "osal_dynamiclib.h" 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | m64p_error osal_dynlib_open(m64p_dynlib_handle *pLibHandle, const char *pccLibraryPath) 33 | { 34 | if (pLibHandle == NULL || pccLibraryPath == NULL) 35 | return M64ERR_INPUT_ASSERT; 36 | 37 | *pLibHandle = LoadLibrary(pccLibraryPath); 38 | 39 | if (*pLibHandle == NULL) 40 | { 41 | char *pchErrMsg; 42 | DWORD dwErr = GetLastError(); 43 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, 44 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); 45 | fprintf(stderr, "LoadLibrary('%s') error: %s\n", pccLibraryPath, pchErrMsg); 46 | LocalFree(pchErrMsg); 47 | return M64ERR_INPUT_NOT_FOUND; 48 | } 49 | 50 | return M64ERR_SUCCESS; 51 | } 52 | 53 | void * osal_dynlib_getproc(m64p_dynlib_handle LibHandle, const char *pccProcedureName) 54 | { 55 | if (pccProcedureName == NULL) 56 | return NULL; 57 | 58 | return GetProcAddress(LibHandle, pccProcedureName); 59 | } 60 | 61 | m64p_error osal_dynlib_close(m64p_dynlib_handle LibHandle) 62 | { 63 | int rval = FreeLibrary(LibHandle); 64 | 65 | if (rval == 0) 66 | { 67 | char *pchErrMsg; 68 | DWORD dwErr = GetLastError(); 69 | FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, 70 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &pchErrMsg, 0, NULL); 71 | fprintf(stderr, "FreeLibrary() error: %s\n", pchErrMsg); 72 | LocalFree(pchErrMsg); 73 | return M64ERR_INTERNAL; 74 | } 75 | 76 | return M64ERR_SUCCESS; 77 | } 78 | #ifdef __cplusplus 79 | } 80 | #endif -------------------------------------------------------------------------------- /.github/workflows/schedule.yml: -------------------------------------------------------------------------------- 1 | name: Z64 RSP - Scheduled 2 | 3 | on: 4 | schedule: 5 | - cron: '0 14 21 * *' 6 | 7 | jobs: 8 | 9 | Linux: 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | include: 14 | - cc: GCC 15 | arch: x64 16 | - cc: GCC 17 | arch: x86 18 | - cc: Clang 19 | arch: x64 20 | - cc: Clang 21 | arch: x86 22 | name: Linux / ${{ matrix.cc }} ${{ matrix.arch }} 23 | runs-on: ubuntu-24.04 24 | if: github.repository == 'mupen64plus/mupen64plus-rsp-z64' 25 | steps: 26 | - uses: actions/checkout@v4 27 | - name: Get build dependencies and arrange the environment 28 | run: | 29 | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core 30 | ./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }} 31 | - name: Build and related stuff, backup binaries 32 | run: | 33 | ./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg 34 | - name: Upload artifact 35 | if: matrix.cc == 'GCC' 36 | uses: actions/upload-artifact@v4 37 | with: 38 | name: ${{ env.PKG_NAME }} 39 | path: pkg/*.tar.gz 40 | 41 | MSYS2: 42 | strategy: 43 | fail-fast: false 44 | matrix: 45 | include: 46 | - cc: GCC 47 | arch: x64 48 | cross: x86_64 49 | env: MINGW64 50 | - cc: GCC 51 | arch: x86 52 | cross: i686 53 | env: MINGW32 54 | - cc: GCC 55 | arch: x64 56 | cross: ucrt-x86_64 57 | env: UCRT64 58 | - cc: Clang 59 | arch: x64 60 | cross: clang-x86_64 61 | env: CLANG64 62 | name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }} 63 | runs-on: windows-2025 64 | if: github.repository == 'mupen64plus/mupen64plus-rsp-z64' 65 | defaults: 66 | run: 67 | shell: msys2 {0} 68 | steps: 69 | - uses: actions/checkout@v4 70 | - uses: msys2/setup-msys2@v2 71 | with: 72 | msystem: ${{ matrix.env }} 73 | update: true 74 | install: >- 75 | git 76 | libtool 77 | make 78 | mingw-w64-${{ matrix.cross }}-toolchain 79 | mingw-w64-${{ matrix.cross }}-ntldd 80 | - name: Build and related stuff, backup binaries 81 | run: | 82 | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core 83 | ./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} 84 | - name: Backup dependencies, etc... 85 | run: | 86 | ./../mupen64plus-core/.github/workflows/scripts/ci_backup_mingw_deps.sh ${{ matrix.env }} 87 | - name: Upload artifact 88 | uses: actions/upload-artifact@v4 89 | with: 90 | name: ${{ env.PKG_NAME }} 91 | path: pkg/* 92 | 93 | Nightly-build: 94 | runs-on: ubuntu-latest 95 | if: github.ref_name == 'master' 96 | needs: [Linux, MSYS2] 97 | steps: 98 | - uses: actions/checkout@v4 99 | - name: Download artifacts 100 | uses: actions/download-artifact@v4 101 | with: 102 | path: binaries 103 | - name: Get some tools 104 | run: | 105 | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core 106 | sudo apt-get update 107 | sudo apt-get -y install hashdeep 108 | - name: Creating new artifacts and update nightly-build 109 | run: | 110 | ./../mupen64plus-core/.github/workflows/scripts/ci_nightly_artifacts.sh 111 | - name: Nightly-build 112 | uses: ncipollo/release-action@v1 113 | with: 114 | prerelease: true 115 | allowUpdates: true 116 | removeArtifacts: true 117 | replacesArtifacts: false 118 | tag: nightly-build 119 | artifacts: pkg/* 120 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Z64 RSP 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - '.{gitattributes,gitignore,travis.yml}' 7 | - '*.md,appveyor.yml,README' 8 | pull_request: 9 | paths-ignore: 10 | - '.{gitattributes,gitignore,travis.yml}' 11 | - '*.md,appveyor.yml,README' 12 | workflow_dispatch: 13 | 14 | jobs: 15 | 16 | Linux: 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | include: 21 | - cc: GCC 22 | arch: x64 23 | - cc: GCC 24 | arch: x86 25 | - cc: Clang 26 | arch: x64 27 | - cc: Clang 28 | arch: x86 29 | name: Linux / ${{ matrix.cc }} ${{ matrix.arch }} 30 | runs-on: ubuntu-24.04 31 | steps: 32 | - uses: actions/checkout@v4 33 | - name: Get build dependencies and arrange the environment 34 | run: | 35 | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core 36 | ./../mupen64plus-core/.github/workflows/scripts/ci_install_ubuntu_deps.sh ${{ matrix.arch }} ${{ matrix.cc }} 37 | - name: Build and related stuff, backup binaries 38 | run: | 39 | ./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} makepkg 40 | - name: Upload artifact 41 | if: matrix.cc == 'GCC' 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: ${{ env.PKG_NAME }} 45 | path: pkg/*.tar.gz 46 | 47 | MSYS2: 48 | strategy: 49 | fail-fast: false 50 | matrix: 51 | include: 52 | - cc: GCC 53 | arch: x64 54 | cross: x86_64 55 | env: MINGW64 56 | - cc: GCC 57 | arch: x86 58 | cross: i686 59 | env: MINGW32 60 | - cc: GCC 61 | arch: x64 62 | cross: ucrt-x86_64 63 | env: UCRT64 64 | - cc: Clang 65 | arch: x64 66 | cross: clang-x86_64 67 | env: CLANG64 68 | name: Windows ${{ matrix.arch }} / MSYS2 ${{ matrix.env }} ${{ matrix.cc }} 69 | runs-on: windows-2025 70 | defaults: 71 | run: 72 | shell: msys2 {0} 73 | steps: 74 | - uses: actions/checkout@v4 75 | - uses: msys2/setup-msys2@v2 76 | with: 77 | msystem: ${{ matrix.env }} 78 | update: true 79 | install: >- 80 | git 81 | libtool 82 | make 83 | mingw-w64-${{ matrix.cross }}-toolchain 84 | mingw-w64-${{ matrix.cross }}-ntldd 85 | - name: Build and related stuff, backup binaries 86 | run: | 87 | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core 88 | ./../mupen64plus-core/.github/workflows/scripts/ci_build.sh ${{ matrix.arch }} ${{ matrix.cc }} 89 | - name: Backup dependencies, etc... 90 | run: | 91 | ./../mupen64plus-core/.github/workflows/scripts/ci_backup_mingw_deps.sh ${{ matrix.env }} 92 | - name: Upload artifact 93 | uses: actions/upload-artifact@v4 94 | with: 95 | name: ${{ env.PKG_NAME }} 96 | path: pkg/* 97 | 98 | Nightly-build: 99 | runs-on: ubuntu-latest 100 | if: github.ref_name == 'master' 101 | needs: [Linux, MSYS2] 102 | steps: 103 | - uses: actions/checkout@v4 104 | - name: Download artifacts 105 | uses: actions/download-artifact@v4 106 | with: 107 | path: binaries 108 | - name: Get some tools 109 | run: | 110 | git clone --depth 1 https://github.com/mupen64plus/mupen64plus-core.git ../mupen64plus-core 111 | sudo apt-get update 112 | sudo apt-get -y install hashdeep 113 | - name: Creating new artifacts and update nightly-build 114 | run: | 115 | ./../mupen64plus-core/.github/workflows/scripts/ci_nightly_artifacts.sh 116 | - name: Nightly-build 117 | uses: ncipollo/release-action@v1 118 | with: 119 | prerelease: true 120 | allowUpdates: true 121 | removeArtifacts: true 122 | replacesArtifacts: false 123 | tag: nightly-build 124 | artifacts: pkg/* 125 | -------------------------------------------------------------------------------- /src/rsp_opinfo.h: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #include "rsp.h" 23 | #include "z64.h" 24 | 25 | struct rsp_regmask_t { 26 | //UINT32 r; 27 | UINT8 v[32]; 28 | UINT32 accu; 29 | UINT8 flag; 30 | }; 31 | 32 | #define RSP_GET_REG_I(i, R) ( (i).r & (1<<(R)) ) 33 | #define RSP_SET_REG_I(i, R) (i).r |= (1<<(R)) 34 | #define RSP_CLEAR_REG_I(i, R) (i).r &= ~(1<<(R)) 35 | 36 | #define RSP_GET_VEC_I(i, R, I) ( (i).v[R] & (1<<(I)) ) 37 | #define RSP_SET_VEC_I(i, R, I) (i).v[R] |= (1<<(I)) 38 | #define RSP_CLEAR_VEC_I(i, R, I) (i).v[R] &= ~(1<<(I)) 39 | 40 | #define RSP_GET_ACCU_I(i, I, P) ( (i).accu & ((P)<<(I)*4) ) 41 | #define RSP_SET_ACCU_I(i, I, P) (i).accu |= ((P)<<(I)*4) 42 | #define RSP_CLEAR_ACCU_I(i, I, P) (i).accu &= ~((P)<<(I)*4) 43 | 44 | #define RSP_GET_FLAG_I(i, R) ( (i).flag & (1<<(R)) ) 45 | #define RSP_SET_FLAG_I(i, R) (i).flag |= (1<<(R)) 46 | #define RSP_CLEAR_FLAG_I(i, R) (i).flag &= ~(1<<(R)) 47 | 48 | #define RSP_OPINFO_JUMP 1 49 | #define RSP_OPINFO_BREAK 2 50 | #define RSP_OPINFO_COND 4 51 | #define RSP_OPINFO_LINK 8 52 | #define RSP_OPINFO_USEPC 16 53 | struct rsp_opinfo_t { 54 | UINT32 op; // original opcode 55 | int op2; // simplified opcode 56 | rsp_regmask_t used; 57 | rsp_regmask_t set; 58 | int flags; 59 | }; 60 | 61 | void rsp_get_opinfo(UINT32 op, rsp_opinfo_t * info); 62 | 63 | #define RSP_BASIC_OFFS 0x000 64 | #define RSP_SPECIAL_OFFS 0x040 65 | #define RSP_LWC2_OFFS 0x0a0 66 | #define RSP_SWC2_OFFS 0x0c0 67 | #define RSP_COP2_1_OFFS 0x080 68 | #define RSP_COP2_2_OFFS 0x100 69 | #define RSP_CONTROL_OFFS 0x140 70 | 71 | 72 | #define RSP_STOP (RSP_CONTROL_OFFS + 0x00) 73 | #define RSP_LOOP (RSP_CONTROL_OFFS + 0x01) 74 | #define RSP_JUMP (RSP_CONTROL_OFFS + 0x02) 75 | #define RSP_CONDJUMP (RSP_CONTROL_OFFS + 0x03) 76 | #define RSP_JUMPLOCAL (RSP_CONTROL_OFFS + 0x04) 77 | #define RSP_CONDJUMPLOCAL (RSP_CONTROL_OFFS + 0x05) 78 | 79 | 80 | #define RSP_SPECIAL (RSP_BASIC_OFFS + 0x00) 81 | #define RSP_REGIMM (RSP_BASIC_OFFS + 0x01) 82 | #define RSP_J (RSP_BASIC_OFFS + 0x02) 83 | #define RSP_JAL (RSP_BASIC_OFFS + 0x03) 84 | #define RSP_BEQ (RSP_BASIC_OFFS + 0x04) 85 | #define RSP_BNE (RSP_BASIC_OFFS + 0x05) 86 | #define RSP_BLEZ (RSP_BASIC_OFFS + 0x06) 87 | #define RSP_BGTZ (RSP_BASIC_OFFS + 0x07) 88 | #define RSP_ADDI (RSP_BASIC_OFFS + 0x08) 89 | #define RSP_ADDIU (RSP_BASIC_OFFS + 0x09) 90 | #define RSP_SLTI (RSP_BASIC_OFFS + 0x0a) 91 | #define RSP_SLTIU (RSP_BASIC_OFFS + 0x0b) 92 | #define RSP_ANDI (RSP_BASIC_OFFS + 0x0c) 93 | #define RSP_ORI (RSP_BASIC_OFFS + 0x0d) 94 | #define RSP_XORI (RSP_BASIC_OFFS + 0x0e) 95 | #define RSP_LUI (RSP_BASIC_OFFS + 0x0f) 96 | #define RSP_COP0 (RSP_BASIC_OFFS + 0x10) 97 | #define RSP_COP2 (RSP_BASIC_OFFS + 0x12) 98 | #define RSP_LB (RSP_BASIC_OFFS + 0x20) 99 | #define RSP_LH (RSP_BASIC_OFFS + 0x21) 100 | #define RSP_LW (RSP_BASIC_OFFS + 0x23) 101 | #define RSP_LBU (RSP_BASIC_OFFS + 0x24) 102 | #define RSP_LHU (RSP_BASIC_OFFS + 0x25) 103 | #define RSP_SB (RSP_BASIC_OFFS + 0x28) 104 | #define RSP_SH (RSP_BASIC_OFFS + 0x29) 105 | #define RSP_SW (RSP_BASIC_OFFS + 0x2b) 106 | #define RSP_LWC2 (RSP_BASIC_OFFS + 0x32) 107 | #define RSP_SWC2 (RSP_BASIC_OFFS + 0x3a) 108 | #define RSP_BLTZ (RSP_BASIC_OFFS + 0x3b) 109 | #define RSP_BGEZ (RSP_BASIC_OFFS + 0x3c) 110 | #define RSP_BGEZAL (RSP_BASIC_OFFS + 0x3d) 111 | 112 | #define RSP_SLL (RSP_SPECIAL_OFFS + 0x00) 113 | #define RSP_SRL (RSP_SPECIAL_OFFS + 0x02) 114 | #define RSP_SRA (RSP_SPECIAL_OFFS + 0x03) 115 | #define RSP_SLLV (RSP_SPECIAL_OFFS + 0x04) 116 | #define RSP_SRLV (RSP_SPECIAL_OFFS + 0x06) 117 | #define RSP_SRAV (RSP_SPECIAL_OFFS + 0x07) 118 | #define RSP_JR (RSP_SPECIAL_OFFS + 0x08) 119 | #define RSP_JALR (RSP_SPECIAL_OFFS + 0x09) 120 | #define RSP_BREAK (RSP_SPECIAL_OFFS + 0x0d) 121 | #define RSP_ADD (RSP_SPECIAL_OFFS + 0x20) 122 | #define RSP_ADDU (RSP_SPECIAL_OFFS + 0x21) 123 | #define RSP_SUB (RSP_SPECIAL_OFFS + 0x22) 124 | #define RSP_SUBU (RSP_SPECIAL_OFFS + 0x23) 125 | #define RSP_AND (RSP_SPECIAL_OFFS + 0x24) 126 | #define RSP_OR (RSP_SPECIAL_OFFS + 0x25) 127 | #define RSP_XOR (RSP_SPECIAL_OFFS + 0x26) 128 | #define RSP_NOR (RSP_SPECIAL_OFFS + 0x27) 129 | #define RSP_SLT (RSP_SPECIAL_OFFS + 0x2a) 130 | #define RSP_SLTU (RSP_SPECIAL_OFFS + 0x2b) 131 | 132 | #define RSP_MFC2 (RSP_COP2_1_OFFS + 0x00) 133 | #define RSP_CFC2 (RSP_COP2_1_OFFS + 0x02) 134 | #define RSP_MTC2 (RSP_COP2_1_OFFS + 0x04) 135 | #define RSP_CTC2 (RSP_COP2_1_OFFS + 0x06) 136 | 137 | 138 | #define RSP_LBV (RSP_LWC2_OFFS + 0x00) 139 | #define RSP_LSV (RSP_LWC2_OFFS + 0x01) 140 | #define RSP_LLV (RSP_LWC2_OFFS + 0x02) 141 | #define RSP_LDV (RSP_LWC2_OFFS + 0x03) 142 | #define RSP_LQV (RSP_LWC2_OFFS + 0x04) 143 | #define RSP_LRV (RSP_LWC2_OFFS + 0x05) 144 | #define RSP_LPV (RSP_LWC2_OFFS + 0x06) 145 | #define RSP_LUV (RSP_LWC2_OFFS + 0x07) 146 | #define RSP_LHV (RSP_LWC2_OFFS + 0x08) 147 | #define RSP_LFV (RSP_LWC2_OFFS + 0x09) 148 | #define RSP_LWV (RSP_LWC2_OFFS + 0x0a) 149 | #define RSP_LTV (RSP_LWC2_OFFS + 0x0b) 150 | 151 | #define RSP_SBV (RSP_SWC2_OFFS + 0x00) 152 | #define RSP_SSV (RSP_SWC2_OFFS + 0x01) 153 | #define RSP_SLV (RSP_SWC2_OFFS + 0x02) 154 | #define RSP_SDV (RSP_SWC2_OFFS + 0x03) 155 | #define RSP_SQV (RSP_SWC2_OFFS + 0x04) 156 | #define RSP_SRV (RSP_SWC2_OFFS + 0x05) 157 | #define RSP_SPV (RSP_SWC2_OFFS + 0x06) 158 | #define RSP_SUV (RSP_SWC2_OFFS + 0x07) 159 | #define RSP_SHV (RSP_SWC2_OFFS + 0x08) 160 | #define RSP_SFV (RSP_SWC2_OFFS + 0x09) 161 | #define RSP_SWV (RSP_SWC2_OFFS + 0x0a) 162 | #define RSP_STV (RSP_SWC2_OFFS + 0x0b) 163 | 164 | #define RSP_VMULF (RSP_COP2_2_OFFS + 0x00) 165 | #define RSP_VMULU (RSP_COP2_2_OFFS + 0x01) 166 | #define RSP_VMUDL (RSP_COP2_2_OFFS + 0x04) 167 | #define RSP_VMUDM (RSP_COP2_2_OFFS + 0x05) 168 | #define RSP_VMUDN (RSP_COP2_2_OFFS + 0x06) 169 | #define RSP_VMUDH (RSP_COP2_2_OFFS + 0x07) 170 | #define RSP_VMACF (RSP_COP2_2_OFFS + 0x08) 171 | #define RSP_VMACU (RSP_COP2_2_OFFS + 0x09) 172 | #define RSP_VMADL (RSP_COP2_2_OFFS + 0x0c) 173 | #define RSP_VMADM (RSP_COP2_2_OFFS + 0x0d) 174 | #define RSP_VMADN (RSP_COP2_2_OFFS + 0x0e) 175 | #define RSP_VMADH (RSP_COP2_2_OFFS + 0x0f) 176 | #define RSP_VADD (RSP_COP2_2_OFFS + 0x10) 177 | #define RSP_VSUB (RSP_COP2_2_OFFS + 0x11) 178 | #define RSP_VABS (RSP_COP2_2_OFFS + 0x13) 179 | #define RSP_VADDC (RSP_COP2_2_OFFS + 0x14) 180 | #define RSP_VSUBC (RSP_COP2_2_OFFS + 0x15) 181 | #define RSP_VSAW (RSP_COP2_2_OFFS + 0x1d) 182 | #define RSP_VLT (RSP_COP2_2_OFFS + 0x20) 183 | #define RSP_VEQ (RSP_COP2_2_OFFS + 0x21) 184 | #define RSP_VNE (RSP_COP2_2_OFFS + 0x22) 185 | #define RSP_VGE (RSP_COP2_2_OFFS + 0x23) 186 | #define RSP_VCL (RSP_COP2_2_OFFS + 0x24) 187 | #define RSP_VCH (RSP_COP2_2_OFFS + 0x25) 188 | #define RSP_VCR (RSP_COP2_2_OFFS + 0x26) 189 | #define RSP_VMRG (RSP_COP2_2_OFFS + 0x27) 190 | #define RSP_VAND (RSP_COP2_2_OFFS + 0x28) 191 | #define RSP_VNAND (RSP_COP2_2_OFFS + 0x29) 192 | #define RSP_VOR (RSP_COP2_2_OFFS + 0x2a) 193 | #define RSP_VNOR (RSP_COP2_2_OFFS + 0x2b) 194 | #define RSP_VXOR (RSP_COP2_2_OFFS + 0x2c) 195 | #define RSP_VNXOR (RSP_COP2_2_OFFS + 0x2d) 196 | #define RSP_VRCP (RSP_COP2_2_OFFS + 0x30) 197 | #define RSP_VRCPL (RSP_COP2_2_OFFS + 0x31) 198 | #define RSP_VRCPH (RSP_COP2_2_OFFS + 0x32) 199 | #define RSP_VMOV (RSP_COP2_2_OFFS + 0x33) 200 | #define RSP_VRSQL (RSP_COP2_2_OFFS + 0x35) 201 | #define RSP_VRSQH (RSP_COP2_2_OFFS + 0x36) 202 | -------------------------------------------------------------------------------- /projects/unix/Makefile: -------------------------------------------------------------------------------- 1 | #/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2 | # * mupen64plus-rsp-z64 - Makefile * 3 | # * Mupen64Plus homepage: https://mupen64plus.org/ * 4 | # * Copyright (C) 2010 Jon Ring * 5 | # * Copyright (C) 2008-2009 Richard Goedeken * 6 | # * Copyright (C) 2007-2008 DarkJeztr Tillin9 * 7 | # * * 8 | # * This program is free software; you can redistribute it and/or modify * 9 | # * it under the terms of the GNU General Public License as published by * 10 | # * the Free Software Foundation; either version 2 of the License, or * 11 | # * (at your option) any later version. * 12 | # * * 13 | # * This program is distributed in the hope that it will be useful, * 14 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of * 15 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 16 | # * GNU General Public License for more details. * 17 | # * * 18 | # * You should have received a copy of the GNU General Public License * 19 | # * along with this program; if not, write to the * 20 | # * Free Software Foundation, Inc., * 21 | # * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 22 | # * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 23 | # Makefile for Z64 RSP plugin in Mupen64plus. 24 | 25 | # detect operating system 26 | UNAME ?= $(shell uname -s) 27 | OS := NONE 28 | ifeq ("$(UNAME)","Linux") 29 | OS = LINUX 30 | SO_EXTENSION = so 31 | SHARED = -shared 32 | endif 33 | ifeq ("$(UNAME)","linux") 34 | OS = LINUX 35 | SO_EXTENSION = so 36 | SHARED = -shared 37 | endif 38 | ifneq ("$(filter GNU hurd,$(UNAME))","") 39 | OS = LINUX 40 | SO_EXTENSION = so 41 | SHARED = -shared 42 | endif 43 | ifeq ("$(UNAME)","Darwin") 44 | OS = OSX 45 | SO_EXTENSION = dylib 46 | SHARED = -bundle 47 | endif 48 | ifeq ("$(UNAME)","FreeBSD") 49 | OS = FREEBSD 50 | SO_EXTENSION = so 51 | SHARED = -shared 52 | endif 53 | ifeq ("$(UNAME)","OpenBSD") 54 | OS = FREEBSD 55 | SO_EXTENSION = so 56 | SHARED = -shared 57 | endif 58 | ifneq ("$(filter GNU/kFreeBSD kfreebsd,$(UNAME))","") 59 | OS = LINUX 60 | SO_EXTENSION = so 61 | SHARED = -shared 62 | endif 63 | ifeq ("$(patsubst MINGW%,MINGW,$(UNAME))","MINGW") 64 | OS = MINGW 65 | SO_EXTENSION = dll 66 | SHARED = -shared 67 | PIC = 0 68 | endif 69 | ifeq ("$(OS)","NONE") 70 | $(error OS type "$(UNAME)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues') 71 | endif 72 | 73 | # detect system architecture 74 | HOST_CPU ?= $(shell uname -m) 75 | NO_ASM ?= 1 76 | CPU := NONE 77 | ifneq ("$(filter x86_64 amd64,$(HOST_CPU))","") 78 | CPU := X86 79 | ifeq ("$(BITS)", "32") 80 | ARCH_DETECTED := 64BITS_32 81 | PIC ?= 0 82 | else 83 | ARCH_DETECTED := 64BITS 84 | PIC ?= 1 85 | endif 86 | endif 87 | ifneq ("$(filter pentium i%86,$(HOST_CPU))","") 88 | CPU := X86 89 | ARCH_DETECTED := 32BITS 90 | PIC ?= 0 91 | endif 92 | ifneq ("$(filter ppc macppc socppc powerpc,$(HOST_CPU))","") 93 | CPU := PPC 94 | ARCH_DETECTED := 32BITS 95 | BIG_ENDIAN := 1 96 | PIC ?= 1 97 | $(warning Architecture "$(HOST_CPU)" not officially supported.') 98 | endif 99 | ifneq ("$(filter ppc64 powerpc64,$(HOST_CPU))","") 100 | CPU := PPC 101 | ARCH_DETECTED := 64BITS 102 | BIG_ENDIAN := 1 103 | PIC ?= 1 104 | $(warning Architecture "$(HOST_CPU)" not officially supported.') 105 | endif 106 | ifneq ("$(filter arm%,$(HOST_CPU))","") 107 | ifeq ("$(filter arm%b,$(HOST_CPU))","") 108 | CPU := ARM 109 | ARCH_DETECTED := 32BITS 110 | PIC ?= 1 111 | $(warning Architecture "$(HOST_CPU)" not officially supported.') 112 | endif 113 | endif 114 | ifneq ("$(filter aarch64 arm64,$(HOST_CPU))","") 115 | CPU := AARCH64 116 | ARCH_DETECTED := 64BITS 117 | PIC ?= 1 118 | $(warning Architecture "$(HOST_CPU)" not officially supported.') 119 | endif 120 | ifeq ("$(CPU)","NONE") 121 | $(error CPU type "$(HOST_CPU)" not supported. Please file bug report at 'https://github.com/mupen64plus/mupen64plus-core/issues') 122 | endif 123 | 124 | HLEVIDEO ?= 0 125 | ifeq ($(HLEVIDEO), 1) 126 | CFLAGS += -DHLEVIDEO 127 | endif 128 | 129 | SRCDIR = ../../src 130 | OBJDIR = _obj$(POSTFIX) 131 | 132 | # base CFLAGS, LDLIBS, and LDFLAGS 133 | OPTFLAGS ?= -O3 -flto 134 | WARNFLAGS ?= -Wall 135 | CFLAGS += $(OPTFLAGS) $(WARNFLAGS) -ffast-math -fno-strict-aliasing -fvisibility=hidden -I../../src 136 | CXXFLAGS += -fvisibility-inlines-hidden 137 | LDFLAGS += $(SHARED) 138 | 139 | # Since we are building a shared library, we must compile with -fPIC on some architectures 140 | # 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 141 | ifeq ($(PIC), 1) 142 | CFLAGS += -fPIC 143 | else 144 | CFLAGS += -fno-PIC 145 | endif 146 | 147 | ifeq ($(BIG_ENDIAN), 1) 148 | CFLAGS += -DM64P_BIG_ENDIAN 149 | endif 150 | 151 | # tweak flags for 32-bit build on 64-bit system 152 | ifeq ($(ARCH_DETECTED), 64BITS_32) 153 | ifeq ($(OS), FREEBSD) 154 | $(error Do not use the BITS=32 option with FreeBSD, use -m32 and -m elf_i386) 155 | endif 156 | ifneq ($(OS), OSX) 157 | ifeq ($(OS), MINGW) 158 | LDFLAGS += -Wl,-m,i386pe 159 | else 160 | CFLAGS += -m32 161 | LDFLAGS += -Wl,-m,elf_i386 162 | endif 163 | endif 164 | endif 165 | 166 | ifeq ($(ARCH_DETECTED), 64BITS) 167 | ifeq ($(OS), MINGW) 168 | LDFLAGS += -Wl,-m,i386pep 169 | endif 170 | endif 171 | 172 | # set special flags per-system 173 | ifeq ($(OS), LINUX) 174 | # only export api symbols 175 | LDFLAGS += -Wl,-version-script,$(SRCDIR)/rsp_api_export.ver 176 | LDLIBS += -ldl 177 | endif 178 | ifeq ($(OS), FREEBSD) 179 | LDLIBS += -lc 180 | endif 181 | ifeq ($(OS), OSX) 182 | OSX_SDK_PATH = $(shell xcrun --sdk macosx --show-sdk-path) 183 | 184 | ifeq ($(CPU), X86) 185 | ifeq ($(ARCH_DETECTED), 64BITS) 186 | CFLAGS += -pipe -arch x86_64 -mmacosx-version-min=10.9 -isysroot $(OSX_SDK_PATH) 187 | LDLIBS += -ldl 188 | else 189 | CFLAGS += -pipe -mmmx -msse -fomit-frame-pointer -arch i686 -mmacosx-version-min=10.9 -isysroot $(OSX_SDK_PATH) 190 | LDLIBS += -ldl 191 | endif 192 | endif 193 | endif 194 | 195 | # set mupen64plus core API header path 196 | ifneq ("$(APIDIR)","") 197 | CFLAGS += "-I$(APIDIR)" 198 | else 199 | TRYDIR = ../../../mupen64plus-core/src/api 200 | ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") 201 | CFLAGS += -I$(TRYDIR) 202 | else 203 | TRYDIR = /usr/local/include/mupen64plus 204 | ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") 205 | CFLAGS += -I$(TRYDIR) 206 | else 207 | TRYDIR = /usr/include/mupen64plus 208 | ifneq ("$(wildcard $(TRYDIR)/m64p_types.h)","") 209 | CFLAGS += -I$(TRYDIR) 210 | else 211 | $(error Mupen64Plus API header files not found! Use makefile parameter APIDIR to force a location.) 212 | endif 213 | endif 214 | endif 215 | endif 216 | 217 | # reduced compile output when running make without V=1 218 | ifneq ($(findstring $(MAKEFLAGS),s),s) 219 | ifndef V 220 | Q_CC = @echo ' CC '$@; 221 | Q_CXX = @echo ' CXX '$@; 222 | Q_LD = @echo ' LD '$@; 223 | endif 224 | endif 225 | 226 | # set base program pointers and flags 227 | CC = $(CROSS_COMPILE)gcc 228 | CXX = $(CROSS_COMPILE)g++ 229 | RM ?= rm -f 230 | INSTALL ?= install 231 | MKDIR ?= mkdir -p 232 | COMPILE.c = $(Q_CC)$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c 233 | COMPILE.cc = $(Q_CXX)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c 234 | LINK.o = $(Q_LD)$(CXX) $(CXXFLAGS) $(LDFLAGS) $(TARGET_ARCH) 235 | 236 | # set special flags for given Makefile parameters 237 | ifeq ($(DEBUG),1) 238 | CFLAGS += -g 239 | INSTALL_STRIP_FLAG ?= 240 | else 241 | INSTALL_STRIP_FLAG ?= -s 242 | endif 243 | 244 | # set installation options 245 | ifeq ($(PREFIX),) 246 | PREFIX := /usr/local 247 | endif 248 | ifeq ($(LIBDIR),) 249 | LIBDIR := $(PREFIX)/lib 250 | endif 251 | ifeq ($(PLUGINDIR),) 252 | PLUGINDIR := $(LIBDIR)/mupen64plus 253 | endif 254 | 255 | # list of source files to compile 256 | SOURCE = \ 257 | $(SRCDIR)/rsp.cpp \ 258 | $(SRCDIR)/rsp_opinfo.cpp \ 259 | $(SRCDIR)/rsp_recomp.cpp \ 260 | $(SRCDIR)/rsp_dasm.cpp \ 261 | $(SRCDIR)/main_rsp.cpp 262 | 263 | ifeq ($(OS), MINGW) 264 | SOURCE += \ 265 | $(SRCDIR)/osal_dynamiclib_win32.c 266 | else 267 | SOURCE += \ 268 | $(SRCDIR)/osal_dynamiclib_unix.c 269 | endif 270 | 271 | # generate a list of object files build, make a temporary directory for them 272 | OBJECTS := $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(filter %.c, $(SOURCE))) 273 | OBJECTS += $(patsubst $(SRCDIR)/%.cpp, $(OBJDIR)/%.o, $(filter %.cpp, $(SOURCE))) 274 | OBJDIRS = $(dir $(OBJECTS)) 275 | $(shell $(MKDIR) $(OBJDIRS)) 276 | 277 | # build targets 278 | TARGET = mupen64plus-rsp-z64$(POSTFIX).$(SO_EXTENSION) 279 | 280 | targets: 281 | @echo "Mupen64Plus-rsp-z64 makefile. " 282 | @echo " Targets:" 283 | @echo " all == Build Mupen64Plus rsp-z64 plugin" 284 | @echo " clean == remove object files" 285 | @echo " rebuild == clean and re-build all" 286 | @echo " install == Install Mupen64Plus rsp-z64 plugin" 287 | @echo " uninstall == Uninstall Mupen64Plus rsp-z64 plugin" 288 | @echo " Options:" 289 | @echo " BITS=32 == build 32-bit binaries on 64-bit machine" 290 | @echo " APIDIR=path == path to find Mupen64Plus Core headers" 291 | @echo " OPTFLAGS=flag == compiler optimization (default: -O3 -flto)" 292 | @echo " WARNFLAGS=flag == compiler warning levels (default: -Wall)" 293 | @echo " PIC=(1|0) == Force enable/disable of position independent code" 294 | @echo " HLEVIDEO=(1|0) == Move task of gfx emulation to a HLE video plugins" 295 | @echo " POSTFIX=name == String added to the name of the the build (default: '')" 296 | @echo " Install Options:" 297 | @echo " PREFIX=path == install/uninstall prefix (default: /usr/local)" 298 | @echo " LIBDIR=path == library prefix (default: PREFIX/lib)" 299 | @echo " PLUGINDIR=path == path to install plugin libraries (default: LIBDIR/mupen64plus)" 300 | @echo " DESTDIR=path == path to prepend to all installation paths (only for packagers)" 301 | @echo " Debugging Options:" 302 | @echo " DEBUG=1 == add debugging symbols" 303 | @echo " V=1 == show verbose compiler output" 304 | 305 | all: $(TARGET) 306 | 307 | install: $(TARGET) 308 | $(INSTALL) -d "$(DESTDIR)$(PLUGINDIR)" 309 | $(INSTALL) -m 0644 $(INSTALL_STRIP_FLAG) $(TARGET) "$(DESTDIR)$(PLUGINDIR)" 310 | 311 | uninstall: 312 | $(RM) "$(DESTDIR)$(PLUGINDIR)/$(TARGET)" 313 | 314 | clean: 315 | $(RM) -r _obj $(OBJDIR) mupen64plus-rsp-z64*.$(SO_EXTENSION) $(TARGET) 316 | 317 | rebuild: clean all 318 | 319 | # build dependency files 320 | CFLAGS += -MD -MP 321 | -include $(OBJECTS:.o=.d) 322 | 323 | CXXFLAGS += $(CFLAGS) 324 | 325 | # standard build rules 326 | $(OBJDIR)/%.o: $(SRCDIR)/%.c 327 | $(COMPILE.c) -o $@ $< 328 | 329 | $(OBJDIR)/%.o: $(SRCDIR)/%.cpp 330 | $(COMPILE.cc) -o $@ $< 331 | 332 | $(TARGET): $(OBJECTS) 333 | $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@ 334 | 335 | .PHONY: all clean install uninstall targets 336 | -------------------------------------------------------------------------------- /src/main_rsp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "m64p_config.h" 28 | #include "m64p_frontend.h" 29 | #include "m64p_plugin.h" 30 | #include "m64p_types.h" 31 | #include "osal_dynamiclib.h" 32 | #include "rsp.h" 33 | #include "z64.h" 34 | 35 | #define RSP_Z64_VERSION 0x020000 36 | #define RSP_PLUGIN_API_VERSION 0x020000 37 | 38 | #define CONFIG_API_VERSION 0x020100 39 | #define CONFIG_PARAM_VERSION 1.00 40 | 41 | #define L_NAME "Z64 RSP Plugin" 42 | 43 | static void (*l_DebugCallback)(void *, int, const char *) = NULL; 44 | static void *l_DebugCallContext = NULL; 45 | static int l_PluginInit = 0; 46 | static m64p_handle l_ConfigRsp; 47 | 48 | ptr_ConfigOpenSection ConfigOpenSection = NULL; 49 | ptr_ConfigDeleteSection ConfigDeleteSection = NULL; 50 | ptr_ConfigSetParameter ConfigSetParameter = NULL; 51 | ptr_ConfigGetParameter ConfigGetParameter = NULL; 52 | ptr_ConfigSetDefaultFloat ConfigSetDefaultFloat; 53 | ptr_ConfigSetDefaultBool ConfigSetDefaultBool = NULL; 54 | ptr_ConfigGetParamBool ConfigGetParamBool = NULL; 55 | ptr_CoreDoCommand CoreDoCommand = NULL; 56 | 57 | bool CFG_HLE_GFX = 0; 58 | bool CFG_HLE_AUD = 0; 59 | 60 | #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) 61 | static void DebugMessage(int level, const char *message, ...) ATTR_FMT(2, 3); 62 | 63 | void DebugMessage(int level, const char *message, ...) 64 | { 65 | char msgbuf[1024]; 66 | va_list args; 67 | 68 | if (l_DebugCallback == NULL) 69 | return; 70 | 71 | va_start(args, message); 72 | vsprintf(msgbuf, message, args); 73 | 74 | (*l_DebugCallback)(l_DebugCallContext, level, msgbuf); 75 | 76 | va_end(args); 77 | } 78 | 79 | #if 0 80 | static void dump() 81 | { 82 | FILE * fp = fopen("rsp.dump", "w"); 83 | assert(fp); 84 | fwrite(rdram, 8*1024, 1024, fp); 85 | fwrite(rsp_dmem, 0x2000, 1, fp); 86 | fwrite(rsp.ext.MI_INTR_REG, 4, 1, fp); 87 | 88 | fwrite(rsp.ext.SP_MEM_ADDR_REG, 4, 1, fp); 89 | fwrite(rsp.ext.SP_DRAM_ADDR_REG, 4, 1, fp); 90 | fwrite(rsp.ext.SP_RD_LEN_REG, 4, 1, fp); 91 | fwrite(rsp.ext.SP_WR_LEN_REG, 4, 1, fp); 92 | fwrite(rsp.ext.SP_STATUS_REG, 4, 1, fp); 93 | fwrite(rsp.ext.SP_DMA_FULL_REG, 4, 1, fp); 94 | fwrite(rsp.ext.SP_DMA_BUSY_REG, 4, 1, fp); 95 | fwrite(rsp.ext.SP_PC_REG, 4, 1, fp); 96 | fwrite(rsp.ext.SP_SEMAPHORE_REG, 4, 1, fp); 97 | 98 | fwrite(rsp.ext.DPC_START_REG, 4, 1, fp); 99 | fwrite(rsp.ext.DPC_END_REG, 4, 1, fp); 100 | fwrite(rsp.ext.DPC_CURRENT_REG, 4, 1, fp); 101 | fwrite(rsp.ext.DPC_STATUS_REG, 4, 1, fp); 102 | fwrite(rsp.ext.DPC_CLOCK_REG, 4, 1, fp); 103 | fwrite(rsp.ext.DPC_BUFBUSY_REG, 4, 1, fp); 104 | fwrite(rsp.ext.DPC_PIPEBUSY_REG, 4, 1, fp); 105 | fwrite(rsp.ext.DPC_TMEM_REG, 4, 1, fp); 106 | fclose(fp); 107 | } 108 | #endif 109 | 110 | void log(m64p_msg_level level, const char *msg, ...) 111 | { 112 | char buf[1024]; 113 | va_list args; 114 | va_start(args, msg); 115 | vsnprintf(buf, 1023, msg, args); 116 | buf[1023]='\0'; 117 | va_end(args); 118 | if (l_DebugCallback) 119 | { 120 | l_DebugCallback(l_DebugCallContext, level, buf); 121 | } 122 | } 123 | 124 | #ifdef __cplusplus 125 | extern "C" { 126 | #endif 127 | 128 | /* DLL-exported functions */ 129 | EXPORT m64p_error CALL PluginStartup(m64p_dynlib_handle CoreLibHandle, void *Context, 130 | void (*DebugCallback)(void *, int, const char *)) 131 | { 132 | float fConfigParamsVersion = 0.0f; 133 | 134 | if (l_PluginInit) 135 | return M64ERR_ALREADY_INIT; 136 | 137 | ///* first thing is to set the callback function for debug info */ 138 | l_DebugCallback = DebugCallback; 139 | l_DebugCallContext = Context; 140 | 141 | ///* Get the core config function pointers from the library handle */ 142 | ConfigOpenSection = (ptr_ConfigOpenSection) osal_dynlib_getproc(CoreLibHandle, "ConfigOpenSection"); 143 | ConfigDeleteSection = (ptr_ConfigDeleteSection) osal_dynlib_getproc(CoreLibHandle, "ConfigDeleteSection"); 144 | ConfigSetParameter = (ptr_ConfigSetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigSetParameter"); 145 | ConfigGetParameter = (ptr_ConfigGetParameter) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParameter"); 146 | ConfigSetDefaultFloat = (ptr_ConfigSetDefaultFloat) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultFloat"); 147 | ConfigSetDefaultBool = (ptr_ConfigSetDefaultBool) osal_dynlib_getproc(CoreLibHandle, "ConfigSetDefaultBool"); 148 | ConfigGetParamBool = (ptr_ConfigGetParamBool) osal_dynlib_getproc(CoreLibHandle, "ConfigGetParamBool"); 149 | CoreDoCommand = (ptr_CoreDoCommand) osal_dynlib_getproc(CoreLibHandle, "CoreDoCommand"); 150 | 151 | if (!ConfigOpenSection || !ConfigDeleteSection || !ConfigSetParameter || !ConfigGetParameter || 152 | !ConfigSetDefaultBool || !ConfigGetParamBool || !ConfigSetDefaultFloat) 153 | return M64ERR_INCOMPATIBLE; 154 | 155 | ///* get a configuration section handle */ 156 | if (ConfigOpenSection("rsp-z64", &l_ConfigRsp) != M64ERR_SUCCESS) 157 | { 158 | DebugMessage(M64MSG_ERROR, "Couldn't open config section 'rsp-z64'"); 159 | return M64ERR_INPUT_NOT_FOUND; 160 | } 161 | 162 | ///* check the section version number */ 163 | if (ConfigGetParameter(l_ConfigRsp, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS) 164 | { 165 | DebugMessage(M64MSG_WARNING, "No version number in 'rsp-z64' config section. Setting defaults."); 166 | ConfigDeleteSection("rsp-z64"); 167 | ConfigOpenSection("rsp-z64", &l_ConfigRsp); 168 | } 169 | else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION)) 170 | { 171 | DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'rsp-z64' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION); 172 | ConfigDeleteSection("rsp-z64"); 173 | ConfigOpenSection("rsp-z64", &l_ConfigRsp); 174 | } 175 | else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f) 176 | { 177 | ///* handle upgrades */ 178 | float fVersion = CONFIG_PARAM_VERSION; 179 | ConfigSetParameter(l_ConfigRsp, "Version", M64TYPE_FLOAT, &fVersion); 180 | DebugMessage(M64MSG_INFO, "Updating parameter set version in 'rsp-z64' config section to %.2f", fVersion); 181 | } 182 | 183 | #ifndef HLEVIDEO 184 | int hlevideo = 0; 185 | #else 186 | int hlevideo = 1; 187 | #endif 188 | 189 | ///* set the default values for this plugin */ 190 | ConfigSetDefaultFloat(l_ConfigRsp, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus z64 RSP Plugin config parameter version number"); 191 | ConfigSetDefaultBool(l_ConfigRsp, "DisplayListToGraphicsPlugin", hlevideo, "Send display lists to the graphics plugin"); 192 | ConfigSetDefaultBool(l_ConfigRsp, "AudioListToAudioPlugin", 0, "Send audio lists to the audio plugin"); 193 | 194 | l_PluginInit = 1; 195 | return M64ERR_SUCCESS; 196 | } 197 | 198 | EXPORT m64p_error CALL PluginShutdown(void) 199 | { 200 | if (!l_PluginInit) 201 | return M64ERR_NOT_INIT; 202 | 203 | ///* reset some local variable */ 204 | l_DebugCallback = NULL; 205 | l_DebugCallContext = NULL; 206 | 207 | l_PluginInit = 0; 208 | return M64ERR_SUCCESS; 209 | } 210 | 211 | EXPORT m64p_error CALL PluginGetVersion(m64p_plugin_type *PluginType, int *PluginVersion, int *APIVersion, const char **PluginNamePtr, int *Capabilities) 212 | { 213 | /* set version info */ 214 | if (PluginType != NULL) 215 | *PluginType = M64PLUGIN_RSP; 216 | 217 | if (PluginVersion != NULL) 218 | *PluginVersion = RSP_Z64_VERSION; 219 | 220 | if (APIVersion != NULL) 221 | *APIVersion = RSP_PLUGIN_API_VERSION; 222 | 223 | if (PluginNamePtr != NULL) 224 | *PluginNamePtr = L_NAME; 225 | 226 | if (Capabilities != NULL) 227 | { 228 | *Capabilities = 0; 229 | } 230 | 231 | return M64ERR_SUCCESS; 232 | } 233 | 234 | EXPORT unsigned int CALL DoRspCycles(unsigned int Cycles) 235 | { 236 | uint32_t TaskType = *(uint32_t*)(z64_rspinfo.DMEM + 0xFC0); 237 | bool compareTaskType = *(uint32_t*)(z64_rspinfo.DMEM + 0x0ff0) != 0; /* Resident Evil 2, null task pointers */ 238 | 239 | #if 0 240 | if (TaskType == 1) { 241 | SDL_Event event; 242 | while (SDL_PollEvent(&event)) { 243 | switch (event.type) { 244 | case SDL_KEYDOWN: 245 | switch (event.key.keysym.sym) { 246 | case 'd': 247 | printf("Dumping !\n"); 248 | dump(); 249 | break; 250 | } 251 | break; 252 | } 253 | } 254 | } 255 | #endif 256 | 257 | if (TaskType == 1 && compareTaskType && CFG_HLE_GFX != 0) { 258 | if (z64_rspinfo.ProcessDlistList != NULL) { 259 | z64_rspinfo.ProcessDlistList(); 260 | } 261 | *z64_rspinfo.SP_STATUS_REG |= (0x0203); 262 | if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { 263 | *z64_rspinfo.MI_INTR_REG |= R4300i_SP_Intr; 264 | z64_rspinfo.CheckInterrupts(); 265 | } 266 | return Cycles; 267 | } 268 | 269 | if (TaskType == 2 && compareTaskType && CFG_HLE_AUD != 0) { 270 | if (z64_rspinfo.ProcessAlistList != NULL) { 271 | z64_rspinfo.ProcessAlistList(); 272 | } 273 | *z64_rspinfo.SP_STATUS_REG |= (0x0203); 274 | if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { 275 | *z64_rspinfo.MI_INTR_REG |= R4300i_SP_Intr; 276 | z64_rspinfo.CheckInterrupts(); 277 | } 278 | return Cycles; 279 | } 280 | 281 | if (z64_rspinfo.CheckInterrupts==NULL) 282 | log(M64MSG_WARNING, "Emulator doesn't provide CheckInterrupts routine"); 283 | return rsp_execute(0x100000); 284 | //return Cycles; 285 | } 286 | 287 | EXPORT void CALL InitiateRSP(RSP_INFO Rsp_Info, unsigned int *CycleCount) 288 | { 289 | CFG_HLE_GFX = ConfigGetParamBool(l_ConfigRsp, "DisplayListToGraphicsPlugin"); 290 | CFG_HLE_AUD = ConfigGetParamBool(l_ConfigRsp, "AudioListToAudioPlugin"); 291 | 292 | log(M64MSG_STATUS, "INITIATE RSP"); 293 | rsp_init(Rsp_Info); 294 | memset(((UINT32*)z64_rspinfo.DMEM), 0, 0x2000); 295 | //*CycleCount = 0; //Causes segfault, doesn't seem to be used anyway 296 | } 297 | 298 | EXPORT void CALL RomClosed(void) 299 | { 300 | extern int rsp_gen_cache_hit; 301 | extern int rsp_gen_cache_miss; 302 | log(M64MSG_STATUS, "cache hit %d miss %d %g%%", rsp_gen_cache_hit, rsp_gen_cache_miss, 303 | rsp_gen_cache_miss*100.0f/rsp_gen_cache_hit); 304 | rsp_gen_cache_hit = rsp_gen_cache_miss = 0; 305 | 306 | #ifdef RSPTIMING 307 | int i,j; 308 | UINT32 op, op2; 309 | 310 | for(i=0; i<0x140;i++) { 311 | if (i>=0x100) 312 | op = (0x12<<26) | (0x10 << 21) | (i&0x3f); 313 | else if (i>=0xc0) 314 | op = (0x3a<<26) | ((i&0x1f)<<11); 315 | else if (i>=0xa0) 316 | op = (0x32<<26) | ((i&0x1f)<<11); 317 | else if (i>=0x80) 318 | op = (0x12<<26) | ((i&0x1f)<<21); 319 | else if (i>=0x40) 320 | op = (0<<26) | (i&0x3f); 321 | else 322 | op = (i&0x3f)<<26; 323 | 324 | char s[128], s2[128]; 325 | rsp_dasm_one(s, 0x800, op); 326 | //rsp_dasm_one(s2, 0x800, op2); 327 | if (rsptimings[i]) 328 | printf("%10g %10g %7d\t%30s\n" 329 | /*"%10g %10g %7d\t%30s\n"*/, 330 | rsptimings[i]/(rspcounts[i]*1.0f), rsptimings[i]*(1.0f), rspcounts[i], s//, 331 | //timings[k]/1.0f/counts[k], counts[k], s2 332 | ); 333 | } 334 | #endif 335 | 336 | //rsp_init(z64_rspinfo); 337 | } 338 | #ifdef __cplusplus 339 | } 340 | #endif 341 | -------------------------------------------------------------------------------- /src/rsp_gen.h: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #include "rsp.h" 23 | 24 | inline UINT32 get_cop0_reg(RSP_REGS & rsp, int reg) 25 | { 26 | if (reg >= 0 && reg < 8) 27 | { 28 | return sp_read_reg(rsp ,reg); 29 | } 30 | else if (reg >= 8 && reg < 16) 31 | { 32 | return n64_dp_reg_r(rsp, reg - 8, 0x00000000); 33 | } 34 | else 35 | { 36 | log(M64MSG_ERROR, "RSP: get_cop0_reg: %d", reg); 37 | } 38 | } 39 | 40 | inline void set_cop0_reg(RSP_REGS & rsp, int reg, UINT32 data) 41 | { 42 | if (reg >= 0 && reg < 8) 43 | { 44 | sp_write_reg(rsp, reg, data); 45 | } 46 | else if (reg >= 8 && reg < 16) 47 | { 48 | n64_dp_reg_w(rsp, reg - 8, data, 0x00000000); 49 | } 50 | else 51 | { 52 | log(M64MSG_ERROR, "RSP: set_cop0_reg: %d, %08X\n", reg, data); 53 | } 54 | } 55 | 56 | static const int vector_elements_2[16][8] = 57 | { 58 | { 0, 1, 2, 3, 4, 5, 6, 7 }, // none 59 | { 0, 1, 2, 3, 4, 5, 6, 7 }, // ??? 60 | { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q 61 | { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q 62 | { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h 63 | { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h 64 | { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h 65 | { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h 66 | { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0 67 | { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1 68 | { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2 69 | { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3 70 | { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4 71 | { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5 72 | { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 73 | { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 74 | }; 75 | INLINE UINT16 SATURATE_ACCUM(int accum, int slice, UINT16 negative, UINT16 positive) 76 | { 77 | if ((INT16)ACCUM_H(accum) < 0) 78 | { 79 | if ((UINT16)(ACCUM_H(accum)) != 0xffff) 80 | { 81 | return negative; 82 | } 83 | else 84 | { 85 | if ((INT16)ACCUM_M(accum) >= 0) 86 | { 87 | return negative; 88 | } 89 | else 90 | { 91 | if (slice == 0) 92 | { 93 | return ACCUM_L(accum); 94 | } 95 | else if (slice == 1) 96 | { 97 | return ACCUM_M(accum); 98 | } 99 | } 100 | } 101 | } 102 | else 103 | { 104 | if ((UINT16)(ACCUM_H(accum)) != 0) 105 | { 106 | return positive; 107 | } 108 | else 109 | { 110 | if ((INT16)ACCUM_M(accum) < 0) 111 | { 112 | return positive; 113 | } 114 | else 115 | { 116 | if (slice == 0) 117 | { 118 | return ACCUM_L(accum); 119 | } 120 | else 121 | { 122 | return ACCUM_M(accum); 123 | } 124 | } 125 | } 126 | } 127 | 128 | return 0; 129 | } 130 | 131 | INLINE UINT16 SATURATE_ACCUM1(int accum, UINT16 negative, UINT16 positive) 132 | { 133 | if ((INT16)ACCUM_H(accum) < 0) 134 | { 135 | if ((UINT16)(ACCUM_H(accum)) != 0xffff) 136 | return negative; 137 | else 138 | { 139 | if ((INT16)ACCUM_M(accum) >= 0) 140 | return negative; 141 | else 142 | return ACCUM_M(accum); 143 | } 144 | } 145 | else 146 | { 147 | if ((UINT16)(ACCUM_H(accum)) != 0) 148 | return positive; 149 | else 150 | { 151 | if ((INT16)ACCUM_M(accum) < 0) 152 | return positive; 153 | else 154 | return ACCUM_M(accum); 155 | } 156 | } 157 | 158 | return 0; 159 | } 160 | 161 | #define WRITEBACK_RESULT() \ 162 | do { \ 163 | VREG_S(VDREG, 0) = vres[0]; \ 164 | VREG_S(VDREG, 1) = vres[1]; \ 165 | VREG_S(VDREG, 2) = vres[2]; \ 166 | VREG_S(VDREG, 3) = vres[3]; \ 167 | VREG_S(VDREG, 4) = vres[4]; \ 168 | VREG_S(VDREG, 5) = vres[5]; \ 169 | VREG_S(VDREG, 6) = vres[6]; \ 170 | VREG_S(VDREG, 7) = vres[7]; \ 171 | } while(0) 172 | 173 | #if 0 174 | inline void rsp_execute_one(UINT32 op) 175 | { 176 | switch (op >> 26) 177 | { 178 | case 0x00: /* SPECIAL */ 179 | { 180 | switch (op & 0x3f) 181 | { 182 | case 0x00: /* SLL */ if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break; 183 | case 0x02: /* SRL */ if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break; 184 | case 0x03: /* SRA */ if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break; 185 | case 0x04: /* SLLV */ if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break; 186 | case 0x06: /* SRLV */ if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break; 187 | case 0x07: /* SRAV */ if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break; 188 | case 0x08: /* JR */ JUMP_PC(RSVAL); break; 189 | case 0x09: /* JALR */ JUMP_PC_L(RSVAL, RDREG); break; 190 | case 0x0d: /* BREAK */ 191 | { 192 | *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE ); 193 | if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { 194 | *z64_rspinfo.MI_INTR_REG |= 1; 195 | z64_rspinfo.CheckInterrupts(); 196 | } 197 | //sp_set_status(0x3); 198 | 199 | #if LOG_INSTRUCTION_EXECUTION 200 | fprintf(exec_output, "\n---------- break ----------\n\n"); 201 | #endif 202 | break; 203 | } 204 | case 0x20: /* ADD */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; 205 | case 0x21: /* ADDU */ if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; 206 | case 0x22: /* SUB */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break; 207 | case 0x23: /* SUBU */ if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break; 208 | case 0x24: /* AND */ if (RDREG) RDVAL = RSVAL & RTVAL; break; 209 | case 0x25: /* OR */ if (RDREG) RDVAL = RSVAL | RTVAL; break; 210 | case 0x26: /* XOR */ if (RDREG) RDVAL = RSVAL ^ RTVAL; break; 211 | case 0x27: /* NOR */ if (RDREG) RDVAL = ~(RSVAL | RTVAL); break; 212 | case 0x2a: /* SLT */ if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break; 213 | case 0x2b: /* SLTU */ if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break; 214 | default: unimplemented_opcode(op); break; 215 | } 216 | break; 217 | } 218 | 219 | case 0x01: /* REGIMM */ 220 | { 221 | switch (RTREG) 222 | { 223 | case 0x00: /* BLTZ */ if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); break; 224 | case 0x01: /* BGEZ */ if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break; 225 | // VP according to the doc, link is performed even when condition fails, 226 | // this sound pretty stupid but let's try it that way 227 | case 0x11: /* BGEZAL */ LINK(31); if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); break; 228 | //case 0x11: /* BGEZAL */ if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break; 229 | default: unimplemented_opcode(op); break; 230 | } 231 | break; 232 | } 233 | 234 | case 0x02: /* J */ JUMP_ABS(UIMM26); break; 235 | case 0x03: /* JAL */ JUMP_ABS_L(UIMM26, 31); break; 236 | case 0x04: /* BEQ */ if (RSVAL == RTVAL) JUMP_REL(SIMM16); break; 237 | case 0x05: /* BNE */ if (RSVAL != RTVAL) JUMP_REL(SIMM16); break; 238 | case 0x06: /* BLEZ */ if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); break; 239 | case 0x07: /* BGTZ */ if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); break; 240 | case 0x08: /* ADDI */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break; 241 | case 0x09: /* ADDIU */ if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break; 242 | case 0x0a: /* SLTI */ if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break; 243 | case 0x0b: /* SLTIU */ if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break; 244 | case 0x0c: /* ANDI */ if (RTREG) RTVAL = RSVAL & UIMM16; break; 245 | case 0x0d: /* ORI */ if (RTREG) RTVAL = RSVAL | UIMM16; break; 246 | case 0x0e: /* XORI */ if (RTREG) RTVAL = RSVAL ^ UIMM16; break; 247 | case 0x0f: /* LUI */ if (RTREG) RTVAL = UIMM16 << 16; break; 248 | 249 | case 0x10: /* COP0 */ 250 | { 251 | switch ((op >> 21) & 0x1f) 252 | { 253 | case 0x00: /* MFC0 */ if (RTREG) RTVAL = get_cop0_reg(RDREG); break; 254 | case 0x04: /* MTC0 */ set_cop0_reg(RDREG, RTVAL); break; 255 | default: 256 | printf("unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op); 257 | break; 258 | } 259 | break; 260 | } 261 | 262 | case 0x12: /* COP2 */ 263 | { 264 | switch ((op >> 21) & 0x1f) 265 | { 266 | case 0x00: /* MFC2 */ 267 | { 268 | // 31 25 20 15 10 6 0 269 | // --------------------------------------------------- 270 | // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | 271 | // --------------------------------------------------- 272 | // 273 | 274 | int el = (op >> 7) & 0xf; 275 | UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); 276 | UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); 277 | if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); 278 | break; 279 | } 280 | case 0x02: /* CFC2 */ 281 | { 282 | // 31 25 20 15 10 0 283 | // ------------------------------------------------ 284 | // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | 285 | // ------------------------------------------------ 286 | // 287 | 288 | // VP to sign extend or to not sign extend ? 289 | //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG]; 290 | if (RTREG) RTVAL = rsp.flag[RDREG]; 291 | break; 292 | } 293 | case 0x04: /* MTC2 */ 294 | { 295 | // 31 25 20 15 10 6 0 296 | // --------------------------------------------------- 297 | // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | 298 | // --------------------------------------------------- 299 | // 300 | 301 | int el = (op >> 7) & 0xf; 302 | VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; 303 | VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; 304 | break; 305 | } 306 | case 0x06: /* CTC2 */ 307 | { 308 | // 31 25 20 15 10 0 309 | // ------------------------------------------------ 310 | // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 | 311 | // ------------------------------------------------ 312 | // 313 | 314 | rsp.flag[RDREG] = RTVAL & 0xffff; 315 | break; 316 | } 317 | 318 | case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: 319 | case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: 320 | { 321 | handle_vector_ops(op); 322 | break; 323 | } 324 | 325 | default: unimplemented_opcode(op); break; 326 | } 327 | break; 328 | } 329 | 330 | case 0x20: /* LB */ if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break; 331 | case 0x21: /* LH */ if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break; 332 | case 0x23: /* LW */ if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break; 333 | case 0x24: /* LBU */ if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break; 334 | case 0x25: /* LHU */ if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break; 335 | case 0x28: /* SB */ WRITE8(RSVAL + SIMM16, RTVAL); break; 336 | case 0x29: /* SH */ WRITE16(RSVAL + SIMM16, RTVAL); break; 337 | case 0x2b: /* SW */ WRITE32(RSVAL + SIMM16, RTVAL); break; 338 | case 0x32: /* LWC2 */ handle_lwc2(op); break; 339 | case 0x3a: /* SWC2 */ handle_swc2(op); break; 340 | 341 | default: 342 | { 343 | unimplemented_opcode(op); 344 | break; 345 | } 346 | } 347 | } 348 | 349 | #endif 350 | -------------------------------------------------------------------------------- /src/rsp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #ifndef _RSP_H_ 23 | #define _RSP_H_ 24 | 25 | #define M64P_PLUGIN_PROTOTYPES 1 26 | #include // sqrt 27 | #include 28 | #include 29 | #include // memset 30 | 31 | #include "m64p_plugin.h" 32 | #include "m64p_types.h" 33 | #include "z64.h" 34 | 35 | #define INLINE inline 36 | 37 | #if defined(__GNUC__) 38 | #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) 39 | #else 40 | #define ATTR_FMT(fmtpos, attrpos) 41 | #endif 42 | 43 | extern void log(m64p_msg_level level, const char *msg, ...) ATTR_FMT(2, 3); 44 | 45 | /* defined in systems/n64.c */ 46 | #define rdram ((UINT32*)z64_rspinfo.RDRAM) 47 | //extern UINT32 *rdram; 48 | #define rsp_imem ((UINT32*)z64_rspinfo.IMEM) 49 | //extern UINT32 *rsp_imem; 50 | #define rsp_dmem ((UINT32*)z64_rspinfo.DMEM) 51 | //extern UINT32 *rsp_dmem; 52 | //extern void dp_full_sync(void); 53 | 54 | #define vi_origin (*(UINT32*)z64_rspinfo.VI_ORIGIN_REG) 55 | //extern UINT32 vi_origin; 56 | #define vi_width (*(UINT32*)z64_rspinfo.VI_WIDTH_REG) 57 | //extern UINT32 vi_width; 58 | #define vi_control (*(UINT32*)z64_rspinfo.VI_STATUS_REG) 59 | //extern UINT32 vi_control; 60 | 61 | #define dp_start (*(UINT32*)z64_rspinfo.DPC_START_REG) 62 | //extern UINT32 dp_start; 63 | #define dp_end (*(UINT32*)z64_rspinfo.DPC_END_REG) 64 | //extern UINT32 dp_end; 65 | #define dp_current (*(UINT32*)z64_rspinfo.DPC_CURRENT_REG) 66 | //extern UINT32 dp_current; 67 | #define dp_status (*(UINT32*)z64_rspinfo.DPC_STATUS_REG) 68 | //extern UINT32 dp_status; 69 | 70 | #define sp_pc (*(UINT32*)z64_rspinfo.SP_PC_REG) 71 | 72 | typedef union 73 | { 74 | UINT64 d[2]; 75 | UINT32 l[4]; 76 | INT16 s[8]; 77 | UINT8 b[16]; 78 | } VECTOR_REG; 79 | 80 | typedef union 81 | { 82 | INT64 q; 83 | INT32 l[2]; 84 | INT16 w[4]; 85 | } ACCUMULATOR_REG; 86 | 87 | typedef struct 88 | { 89 | // vectors first , need to be memory aligned for sse 90 | VECTOR_REG v[32]; 91 | ACCUMULATOR_REG accum[8]; 92 | 93 | //UINT32 pc; 94 | UINT32 r[32]; 95 | UINT16 flag[4]; 96 | 97 | INT32 square_root_res; 98 | INT32 square_root_high; 99 | INT32 reciprocal_res; 100 | INT32 reciprocal_high; 101 | 102 | UINT32 ppc; 103 | UINT32 nextpc; 104 | 105 | UINT32 step_count; 106 | 107 | int inval_gen; 108 | 109 | RSP_INFO ext; 110 | } RSP_REGS; 111 | 112 | #define z64_rspinfo (rsp.ext) 113 | 114 | int rsp_execute(int cycles); 115 | void rsp_reset(void); 116 | void rsp_init(RSP_INFO info); 117 | offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op); 118 | 119 | extern UINT32 sp_read_reg(UINT32 reg); 120 | extern void sp_write_reg(UINT32 reg, UINT32 data); 121 | // extern READ32_HANDLER( n64_dp_reg_r ); 122 | // extern WRITE32_HANDLER( n64_dp_reg_w ); 123 | 124 | #define RSREG ((op >> 21) & 0x1f) 125 | #define RTREG ((op >> 16) & 0x1f) 126 | #define RDREG ((op >> 11) & 0x1f) 127 | #define SHIFT ((op >> 6) & 0x1f) 128 | 129 | #define RSVAL (rsp.r[RSREG]) 130 | #define RTVAL (rsp.r[RTREG]) 131 | #define RDVAL (rsp.r[RDREG]) 132 | 133 | #define _RSREG(op) ((op >> 21) & 0x1f) 134 | #define _RTREG(op) ((op >> 16) & 0x1f) 135 | #define _RDREG(op) ((op >> 11) & 0x1f) 136 | #define _SHIFT(op) ((op >> 6) & 0x1f) 137 | 138 | #define _RSVAL(op) (rsp.r[_RSREG(op)]) 139 | #define _RTVAL(op) (rsp.r[_RTREG(op)]) 140 | #define _RDVAL(op) (rsp.r[_RDREG(op)]) 141 | 142 | #define SIMM16 ((INT32)(INT16)(op)) 143 | #define UIMM16 ((UINT16)(op)) 144 | #define UIMM26 (op & 0x03ffffff) 145 | 146 | #define _SIMM16(op) ((INT32)(INT16)(op)) 147 | #define _UIMM16(op) ((UINT16)(op)) 148 | #define _UIMM26(op) (op & 0x03ffffff) 149 | 150 | 151 | /*#define _JUMP(pc) \ 152 | if ((GENTRACE("_JUMP %x\n", rsp.nextpc), 1) && rsp_jump(rsp.nextpc)) return 1; \ 153 | if (rsp.inval_gen || sp_pc != pc+8) return 0; 154 | */ 155 | 156 | #define CARRY_FLAG(x) ((rsp.flag[0] & (1 << ((x)))) ? 1 : 0) 157 | #define CLEAR_CARRY_FLAGS() { rsp.flag[0] &= ~0xff; } 158 | #define SET_CARRY_FLAG(x) { rsp.flag[0] |= (1 << ((x))); } 159 | #define CLEAR_CARRY_FLAG(x) { rsp.flag[0] &= ~(1 << ((x))); } 160 | 161 | #define COMPARE_FLAG(x) ((rsp.flag[1] & (1 << ((x)))) ? 1 : 0) 162 | #define CLEAR_COMPARE_FLAGS() { rsp.flag[1] &= ~0xff; } 163 | #define SET_COMPARE_FLAG(x) { rsp.flag[1] |= (1 << ((x))); } 164 | #define CLEAR_COMPARE_FLAG(x) { rsp.flag[1] &= ~(1 << ((x))); } 165 | 166 | #define ZERO_FLAG(x) ((rsp.flag[0] & (1 << (8+(x)))) ? 1 : 0) 167 | #define CLEAR_ZERO_FLAGS() { rsp.flag[0] &= ~0xff00; } 168 | #define SET_ZERO_FLAG(x) { rsp.flag[0] |= (1 << (8+(x))); } 169 | #define CLEAR_ZERO_FLAG(x) { rsp.flag[0] &= ~(1 << (8+(x))); } 170 | 171 | //#define rsp z64_rsp // to avoid namespace collision with other libs 172 | extern RSP_REGS rsp __attribute__((aligned(16))); 173 | 174 | 175 | //#define ROPCODE(pc) cpu_readop32(pc) 176 | #define ROPCODE(pc) program_read_dword_32be(pc | 0x1000) 177 | 178 | INLINE UINT8 program_read_byte_32be(UINT32 address) 179 | { 180 | return ((UINT8*)z64_rspinfo.DMEM)[(address&0x1fff)^3]; 181 | } 182 | 183 | INLINE UINT16 program_read_word_32be(UINT32 address) 184 | { 185 | return ((UINT16*)z64_rspinfo.DMEM)[((address&0x1fff)>>1)^1]; 186 | } 187 | 188 | INLINE UINT32 program_read_dword_32be(UINT32 address) 189 | { 190 | return ((UINT32*)z64_rspinfo.DMEM)[(address&0x1fff)>>2]; 191 | } 192 | 193 | INLINE void program_write_byte_32be(UINT32 address, UINT8 data) 194 | { 195 | ((UINT8*)z64_rspinfo.DMEM)[(address&0x1fff)^3] = data; 196 | } 197 | 198 | INLINE void program_write_word_32be(UINT32 address, UINT16 data) 199 | { 200 | ((UINT16*)z64_rspinfo.DMEM)[((address&0x1fff)>>1)^1] = data; 201 | } 202 | 203 | INLINE void program_write_dword_32be(UINT32 address, UINT32 data) 204 | { 205 | ((UINT32*)z64_rspinfo.DMEM)[(address&0x1fff)>>2] = data; 206 | } 207 | 208 | INLINE UINT8 READ8(UINT32 address) 209 | { 210 | address = 0x04000000 | (address & 0xfff); 211 | return program_read_byte_32be(address); 212 | } 213 | 214 | INLINE UINT16 READ16(UINT32 address) 215 | { 216 | address = 0x04000000 | (address & 0xfff); 217 | 218 | if (address & 1) 219 | { 220 | //osd_die("RSP: READ16: unaligned %08X at %08X\n", address, rsp.ppc); 221 | return ((program_read_byte_32be(address+0) & 0xff) << 8) | (program_read_byte_32be(address+1) & 0xff); 222 | } 223 | 224 | return program_read_word_32be(address); 225 | } 226 | 227 | INLINE UINT32 READ32(UINT32 address) 228 | { 229 | address = 0x04000000 | (address & 0xfff); 230 | 231 | if (address & 3) 232 | { 233 | //fatalerror("RSP: READ32: unaligned %08X at %08X\n", address, rsp.ppc); 234 | return ((program_read_byte_32be(address + 0) & 0xff) << 24) | 235 | ((program_read_byte_32be(address + 1) & 0xff) << 16) | 236 | ((program_read_byte_32be(address + 2) & 0xff) << 8) | 237 | ((program_read_byte_32be(address + 3) & 0xff) << 0); 238 | } 239 | 240 | return program_read_dword_32be(address); 241 | } 242 | 243 | 244 | INLINE void WRITE8(UINT32 address, UINT8 data) 245 | { 246 | address = 0x04000000 | (address & 0xfff); 247 | program_write_byte_32be(address, data); 248 | } 249 | 250 | INLINE void WRITE16(UINT32 address, UINT16 data) 251 | { 252 | address = 0x04000000 | (address & 0xfff); 253 | 254 | if (address & 1) 255 | { 256 | //fatalerror("RSP: WRITE16: unaligned %08X, %04X at %08X\n", address, data, rsp.ppc); 257 | program_write_byte_32be(address + 0, (data >> 8) & 0xff); 258 | program_write_byte_32be(address + 1, (data >> 0) & 0xff); 259 | return; 260 | } 261 | 262 | program_write_word_32be(address, data); 263 | } 264 | 265 | INLINE void WRITE32(UINT32 address, UINT32 data) 266 | { 267 | address = 0x04000000 | (address & 0xfff); 268 | 269 | if (address & 3) 270 | { 271 | //fatalerror("RSP: WRITE32: unaligned %08X, %08X at %08X\n", address, data, rsp.ppc); 272 | program_write_byte_32be(address + 0, (data >> 24) & 0xff); 273 | program_write_byte_32be(address + 1, (data >> 16) & 0xff); 274 | program_write_byte_32be(address + 2, (data >> 8) & 0xff); 275 | program_write_byte_32be(address + 3, (data >> 0) & 0xff); 276 | return; 277 | } 278 | 279 | program_write_dword_32be(address, data); 280 | } 281 | 282 | int rsp_jump(int pc); 283 | void rsp_invalidate(int begin, int len); 284 | void rsp_execute_one(UINT32 op); 285 | 286 | 287 | 288 | #define JUMP_ABS(addr) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); } 289 | #define JUMP_ABS_L(addr,l) { rsp.nextpc = 0x04001000 | (((addr) << 2) & 0xfff); rsp.r[l] = sp_pc + 4; } 290 | #define JUMP_REL(offset) { rsp.nextpc = 0x04001000 | ((sp_pc + ((offset) << 2)) & 0xfff); } 291 | #define JUMP_REL_L(offset,l) { rsp.nextpc = 0x04001000 | ((sp_pc + ((offset) << 2)) & 0xfff); rsp.r[l] = sp_pc + 4; } 292 | #define JUMP_PC(addr) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); } 293 | #define JUMP_PC_L(addr,l) { rsp.nextpc = 0x04001000 | ((addr) & 0xfff); rsp.r[l] = sp_pc + 4; } 294 | #define LINK(l) rsp.r[l] = sp_pc + 4 295 | 296 | #define VDREG ((op >> 6) & 0x1f) 297 | #define VS1REG ((op >> 11) & 0x1f) 298 | #define VS2REG ((op >> 16) & 0x1f) 299 | #define EL ((op >> 21) & 0xf) 300 | 301 | #define VREG_B(reg, offset) rsp.v[(reg)].b[((offset)^1)] 302 | #define VREG_S(reg, offset) rsp.v[(reg)].s[((offset))] 303 | #define VREG_L(reg, offset) rsp.v[(reg)].l[((offset))] 304 | 305 | #define VEC_EL_1(x,z) (z) //(vector_elements_1[(x)][(z)]) 306 | #define VEC_EL_2(x,z) (vector_elements_2[(x)][(z)]) 307 | 308 | #define ACCUM(x) rsp.accum[((x))].q 309 | #define ACCUM_H(x) rsp.accum[((x))].w[3] 310 | #define ACCUM_M(x) rsp.accum[((x))].w[2] 311 | #define ACCUM_L(x) rsp.accum[((x))].w[1] 312 | 313 | void unimplemented_opcode(UINT32 op); 314 | void handle_vector_ops(UINT32 op); 315 | UINT32 get_cop0_reg(int reg); 316 | void set_cop0_reg(int reg, UINT32 data); 317 | void handle_lwc2(UINT32 op); 318 | void handle_swc2(UINT32 op); 319 | 320 | INLINE UINT32 n64_dp_reg_r(UINT32 offset, UINT32 dummy) 321 | { 322 | switch (offset) 323 | { 324 | case 0x00/4: // DP_START_REG 325 | return dp_start; 326 | 327 | case 0x04/4: // DP_END_REG 328 | return dp_end; 329 | 330 | case 0x08/4: // DP_CURRENT_REG 331 | return dp_current; 332 | 333 | case 0x0c/4: // DP_STATUS_REG 334 | return dp_status; 335 | 336 | case 0x10/4: // DP_CLOCK_REG 337 | return *z64_rspinfo.DPC_CLOCK_REG; 338 | 339 | default: 340 | log(M64MSG_WARNING, "dp_reg_r: %08X\n", offset); 341 | break; 342 | } 343 | 344 | return 0; 345 | } 346 | INLINE void n64_dp_reg_w(UINT32 offset, UINT32 data, UINT32 dummy) 347 | { 348 | switch (offset) 349 | { 350 | case 0x00/4: // DP_START_REG 351 | dp_start = data; 352 | dp_current = dp_start; 353 | break; 354 | 355 | case 0x04/4: // DP_END_REG 356 | dp_end = data; 357 | //rdp_process_list(); 358 | if (dp_end= 2 385 | static __inline__ unsigned long long RDTSC(void) 386 | { 387 | unsigned long long int x; 388 | __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x)); 389 | return x; 390 | } 391 | // inline volatile uint64_t RDTSC() { 392 | // register uint64_t TSC asm("eax"); 393 | // asm volatile (".byte 15, 49" : : : "eax", "edx"); 394 | // return TSC; 395 | // } 396 | // #define RDTSC1(n) __asm__ __volatile__("rdtsc" : "=a" (n): ) 397 | // #define RDTSC2(n) __asm__ __volatile__ ("rdtsc\nmov %%edx,%%eax" : "=a" (n): ) 398 | // inline void RDTSC(uint64_t& a) { uint32_t b, c; RDTSC1(b); RDTSC2(c); 399 | // a = (((uint64_t)c)<<32) | b; } 400 | #elif defined(INTEL86) && defined WIN32 401 | #define rdtsc __asm __emit 0fh __asm __emit 031h 402 | #define cpuid __asm __emit 0fh __asm __emit 0a2h 403 | inline uint64_t RDTSC() { 404 | static uint32_t temp; 405 | __asm { 406 | push edx 407 | push eax 408 | rdtsc 409 | mov temp, eax 410 | pop eax 411 | pop edx 412 | } 413 | return temp; 414 | } 415 | #else 416 | #define RDTSC(n) n=0 417 | #endif 418 | 419 | #ifdef GENTRACE 420 | #undef GENTRACE 421 | #include 422 | 423 | inline void GENTRACE(const char * s, ...) ATTR_FMT(1, 2); 424 | 425 | void GENTRACE(const char * s, ...) 426 | { 427 | va_list ap; 428 | va_start(ap, s); 429 | vfprintf(stderr, s, ap); 430 | va_end(ap); 431 | int i; 432 | for (i=0; i<32; i++) 433 | fprintf(stderr, "r%d=%x ", i, rsp.r[i]); 434 | fprintf(stderr, "\n"); 435 | for (i=0; i<32; i++) 436 | fprintf(stderr, "v%d=%x %x %x %x %x %x %x %x ", i, 437 | (UINT16)rsp.v[i].s[0], 438 | (UINT16)rsp.v[i].s[1], 439 | (UINT16)rsp.v[i].s[2], 440 | (UINT16)rsp.v[i].s[3], 441 | (UINT16)rsp.v[i].s[4], 442 | (UINT16)rsp.v[i].s[5], 443 | (UINT16)rsp.v[i].s[6], 444 | (UINT16)rsp.v[i].s[7] 445 | ); 446 | fprintf(stderr, "\n"); 447 | 448 | fprintf(stderr, "f0=%x f1=%x f2=%x f3=%x\n", rsp.flag[0], 449 | rsp.flag[1],rsp.flag[2],rsp.flag[3]); 450 | } 451 | #endif 452 | //#define GENTRACE printf 453 | //#define GENTRACE 454 | 455 | #ifdef RSPTIMING 456 | extern uint64_t rsptimings[512]; 457 | extern int rspcounts[512]; 458 | #endif 459 | 460 | #endif // ifndef _RSP_H_ 461 | -------------------------------------------------------------------------------- /src/rsp_opinfo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #include 23 | 24 | #include "m64p_types.h" 25 | #include "rsp.h" 26 | #include "rsp_opinfo.h" 27 | 28 | static const int vector_elements_2[16][8] = 29 | { 30 | { 0, 1, 2, 3, 4, 5, 6, 7 }, // none 31 | { 0, 1, 2, 3, 4, 5, 6, 7 }, // ??? 32 | { 0, 0, 2, 2, 4, 4, 6, 6 }, // 0q 33 | { 1, 1, 3, 3, 5, 5, 7, 7 }, // 1q 34 | { 0, 0, 0, 0, 4, 4, 4, 4 }, // 0h 35 | { 1, 1, 1, 1, 5, 5, 5, 5 }, // 1h 36 | { 2, 2, 2, 2, 6, 6, 6, 6 }, // 2h 37 | { 3, 3, 3, 3, 7, 7, 7, 7 }, // 3h 38 | { 0, 0, 0, 0, 0, 0, 0, 0 }, // 0 39 | { 1, 1, 1, 1, 1, 1, 1, 1 }, // 1 40 | { 2, 2, 2, 2, 2, 2, 2, 2 }, // 2 41 | { 3, 3, 3, 3, 3, 3, 3, 3 }, // 3 42 | { 4, 4, 4, 4, 4, 4, 4, 4 }, // 4 43 | { 5, 5, 5, 5, 5, 5, 5, 5 }, // 5 44 | { 6, 6, 6, 6, 6, 6, 6, 6 }, // 6 45 | { 7, 7, 7, 7, 7, 7, 7, 7 }, // 7 46 | }; 47 | 48 | void rsp_get_opinfo(UINT32 op, rsp_opinfo_t * info) 49 | { 50 | int op2; 51 | int i; 52 | info->op = op; 53 | switch (op>>26) { 54 | case 0: /* SPECIAL */ 55 | op2 = RSP_SPECIAL_OFFS + (op&0x3f); 56 | break; 57 | case 0x12: /* COP2 */ 58 | if (((op>>21)&0x1f) >= 0x10) 59 | op2 = RSP_COP2_2_OFFS + (op & 0x3f); 60 | else 61 | op2 = RSP_COP2_1_OFFS + ((op >> 21) & 0x1f); 62 | break; 63 | case 0x32: /* LWC2 */ 64 | op2 = RSP_LWC2_OFFS + ((op>>11)&0x1f); 65 | break; 66 | case 0x3a: /* SWC2 */ 67 | op2 = RSP_SWC2_OFFS + ((op>>11)&0x1f); 68 | break; 69 | default: 70 | op2 = RSP_BASIC_OFFS + (op>>26); 71 | if (op2 == RSP_REGIMM) { 72 | switch (RTREG) 73 | { 74 | case 0x00: /* BLTZ */ 75 | op2 = RSP_BLTZ; 76 | break; 77 | case 0x01: /* BGEZ */ 78 | op2 = RSP_BGEZ; 79 | break; 80 | case 0x11: /* BGEZAL */ 81 | op2 = RSP_BGEZAL; 82 | break; 83 | } 84 | } 85 | } 86 | info->op2 = op2; 87 | 88 | memset(&info->used, 0, sizeof(info->used)); 89 | memset(&info->set, 0, sizeof(info->set)); 90 | info->used.accu = info->used.flag = 0; 91 | info->set.accu = info->set.flag = 0; 92 | info->flags = 0; 93 | 94 | int dest = (op >> 16) & 0x1f; 95 | int index = (op >> 7) & 0xf; 96 | int offset = (op & 0x7f); 97 | if (offset & 0x40) 98 | offset |= 0xffffffc0; 99 | 100 | switch(op2) { 101 | case RSP_SPECIAL: 102 | case RSP_BLTZ: 103 | info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC; 104 | break; 105 | case RSP_BGEZ: 106 | info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC; 107 | break; 108 | case RSP_BGEZAL: 109 | info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_LINK | RSP_OPINFO_USEPC; 110 | break; 111 | case RSP_J: 112 | info->flags = RSP_OPINFO_JUMP; 113 | break; 114 | case RSP_JAL: 115 | info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_LINK | RSP_OPINFO_USEPC; 116 | break; 117 | case RSP_BEQ: 118 | case RSP_BNE: 119 | case RSP_BLEZ: 120 | case RSP_BGTZ: 121 | info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_COND | RSP_OPINFO_USEPC; 122 | break; 123 | case RSP_ADDI: 124 | case RSP_ADDIU: 125 | case RSP_SLTI: 126 | case RSP_SLTIU: 127 | case RSP_ANDI: 128 | case RSP_ORI: 129 | case RSP_XORI: 130 | case RSP_LUI: 131 | case RSP_COP0: 132 | case RSP_LB: 133 | case RSP_LH: 134 | case RSP_LW: 135 | case RSP_LBU: 136 | case RSP_LHU: 137 | case RSP_SB: 138 | case RSP_SH: 139 | case RSP_SW: 140 | break; 141 | 142 | case RSP_SLL: 143 | case RSP_SRL: 144 | case RSP_SRA: 145 | case RSP_SLLV: 146 | case RSP_SRLV: 147 | case RSP_SRAV: 148 | break; 149 | 150 | case RSP_JR: 151 | info->flags = RSP_OPINFO_JUMP; 152 | break; 153 | case RSP_JALR: 154 | info->flags = RSP_OPINFO_JUMP | RSP_OPINFO_LINK | RSP_OPINFO_USEPC; 155 | break; 156 | case RSP_BREAK: 157 | info->flags = RSP_OPINFO_BREAK; 158 | break; 159 | 160 | case RSP_ADD: 161 | case RSP_ADDU: 162 | case RSP_SUB: 163 | case RSP_SUBU: 164 | case RSP_AND: 165 | case RSP_OR: 166 | case RSP_XOR: 167 | case RSP_NOR: 168 | case RSP_SLT: 169 | case RSP_SLTU: 170 | break; 171 | 172 | case RSP_MFC2: 173 | { 174 | int el = op >> 7; 175 | RSP_SET_VEC_I(info->used, VS1REG, ((el+0)&0xf)>>1); 176 | RSP_SET_VEC_I(info->used, VS1REG, ((el+1)&0xf)>>1); 177 | break; 178 | } 179 | case RSP_CFC2: 180 | RSP_SET_FLAG_I(info->used, RDREG & 3); 181 | break; 182 | case RSP_MTC2: 183 | { 184 | int el = op >> 7; 185 | RSP_SET_VEC_I(info->set, VS1REG, ((el+0)&0xf)>>1); 186 | RSP_SET_VEC_I(info->set, VS1REG, ((el+1)&0xf)>>1); 187 | break; 188 | } 189 | case RSP_CTC2: 190 | RSP_SET_FLAG_I(info->set, RDREG & 3); 191 | break; 192 | 193 | 194 | case RSP_LBV: 195 | RSP_SET_VEC_I(info->set, dest, index>>1); 196 | break; 197 | case RSP_LSV: 198 | for (i=index; iset, dest, (i>>1)&7); 200 | break; 201 | case RSP_LLV: 202 | for (i=index; iset, dest, (i>>1)&7); 204 | break; 205 | case RSP_LDV: 206 | for (i=index; iset, dest, (i>>1)&7); 208 | break; 209 | case RSP_LQV: 210 | case RSP_LRV: 211 | // WARNING WARNING WARNING 212 | // we assume this instruction always used to load the full vector 213 | // i.e. the address is always 16 bytes aligned 214 | // for (i=0; i<8; i++) 215 | // RSP_SET_VEC_I(info->set, dest, i); 216 | break; 217 | case RSP_LPV: 218 | case RSP_LUV: 219 | case RSP_LHV: 220 | case RSP_LWV: 221 | for (i=0; i<8; i++) 222 | RSP_SET_VEC_I(info->set, dest, i); 223 | break; 224 | case RSP_LFV: 225 | for (i=(index>>1); i<(index>>1)+4; i++) 226 | RSP_SET_VEC_I(info->set, dest, i); 227 | break; 228 | case RSP_LTV: 229 | { 230 | // 31 25 20 15 10 6 0 231 | // -------------------------------------------------- 232 | // | 110010 | BBBBB | TTTTT | 01011 | IIII | Offset | 233 | // -------------------------------------------------- 234 | // 235 | // Loads one element to maximum of 8 vectors, while incrementing element index 236 | 237 | // FIXME: has a small problem with odd indices 238 | 239 | int element; 240 | int vs = dest; 241 | int ve = dest + 8; 242 | if (ve > 32) 243 | ve = 32; 244 | 245 | element = 7 - (index >> 1); 246 | 247 | if (index & 1) 248 | log(M64MSG_ERROR, "RSP: LTV: index = %d\n", index); 249 | 250 | for (i=vs; i < ve; i++) 251 | { 252 | element = ((8 - (index >> 1) + (i-vs)) << 1); 253 | RSP_SET_VEC_I(info->set, i, (element & 0xf)>>1); 254 | RSP_SET_VEC_I(info->set, i, ((element+1) & 0xf)>>1); 255 | } 256 | break; 257 | } 258 | 259 | case RSP_SBV: 260 | RSP_SET_VEC_I(info->used, dest, index>>1); 261 | break; 262 | case RSP_SSV: 263 | for (i=index; iused, dest, (i>>1)&7); 265 | break; 266 | case RSP_SLV: 267 | for (i=index; iused, dest, (i>>1)&7); 269 | break; 270 | case RSP_SDV: 271 | for (i=index; iused, dest, (i>>1)&7); 273 | break; 274 | case RSP_SQV: 275 | case RSP_SRV: 276 | // WARNING WARNING WARNING 277 | // we assume this instruction always used to store the full vector 278 | // i.e. the address is always 16 bytes aligned 279 | for (i=0; i<8; i++) 280 | RSP_SET_VEC_I(info->used, dest, i); 281 | break; 282 | case RSP_SPV: 283 | case RSP_SUV: 284 | case RSP_SHV: 285 | case RSP_SWV: 286 | for (i=0; i<8; i++) 287 | RSP_SET_VEC_I(info->used, dest, i); 288 | break; 289 | case RSP_SFV: 290 | for (i=(index>>1); i<(index>>1)+4; i++) 291 | RSP_SET_VEC_I(info->used, dest, i); 292 | break; 293 | case RSP_STV: 294 | { 295 | // 31 25 20 15 10 6 0 296 | // -------------------------------------------------- 297 | // | 111010 | BBBBB | TTTTT | 01011 | IIII | Offset | 298 | // -------------------------------------------------- 299 | // 300 | // Stores one element from maximum of 8 vectors, while incrementing element index 301 | 302 | int element; 303 | int vs = dest; 304 | int ve = dest + 8; 305 | if (ve > 32) 306 | ve = 32; 307 | 308 | element = 8 - (index >> 1); 309 | if (index & 0x1) 310 | log(M64MSG_ERROR, "RSP: STV: index = %d at %08X\n", index, rsp.ppc); 311 | 312 | for (i=vs; i < ve; i++) 313 | { 314 | RSP_SET_VEC_I(info->used, i, element & 0x7); 315 | element++; 316 | } 317 | break; 318 | } 319 | 320 | case RSP_VMULF: 321 | case RSP_VMULU: 322 | case RSP_VMUDL: 323 | case RSP_VMUDM: 324 | case RSP_VMUDN: 325 | case RSP_VMUDH: 326 | { 327 | for (i=0; i < 8; i++) 328 | { 329 | int sel = VEC_EL_2(EL, i); 330 | RSP_SET_VEC_I(info->used, VS1REG, i); 331 | RSP_SET_VEC_I(info->used, VS2REG, sel); 332 | RSP_SET_VEC_I(info->set, VDREG, i); 333 | RSP_SET_ACCU_I(info->set, i, 14); 334 | } 335 | break; 336 | } 337 | case RSP_VMACF: 338 | case RSP_VMACU: 339 | case RSP_VMADL: 340 | case RSP_VMADM: 341 | case RSP_VMADN: 342 | case RSP_VMADH: 343 | { 344 | for (i=0; i < 8; i++) 345 | { 346 | int sel = VEC_EL_2(EL, i); 347 | RSP_SET_VEC_I(info->used, VS1REG, i); 348 | RSP_SET_VEC_I(info->used, VS2REG, sel); 349 | RSP_SET_VEC_I(info->set, VDREG, i); 350 | RSP_SET_ACCU_I(info->used, i, 14); 351 | RSP_SET_ACCU_I(info->set, i, 14); 352 | } 353 | break; 354 | } 355 | case RSP_VADD: 356 | case RSP_VSUB: 357 | { 358 | for (i=0; i < 8; i++) 359 | { 360 | int sel = VEC_EL_2(EL, i); 361 | RSP_SET_VEC_I(info->used, VS1REG, i); 362 | RSP_SET_VEC_I(info->used, VS2REG, sel); 363 | RSP_SET_VEC_I(info->set, VDREG, i); 364 | RSP_SET_ACCU_I(info->set, i, 2); 365 | } 366 | RSP_SET_FLAG_I(info->used, 0); 367 | RSP_SET_FLAG_I(info->set, 0); 368 | break; 369 | } 370 | case RSP_VABS: 371 | { 372 | for (i=0; i < 8; i++) 373 | { 374 | int sel = VEC_EL_2(EL, i); 375 | RSP_SET_VEC_I(info->used, VS1REG, i); 376 | RSP_SET_VEC_I(info->used, VS2REG, sel); 377 | RSP_SET_VEC_I(info->set, VDREG, i); 378 | RSP_SET_ACCU_I(info->set, i, 2); 379 | } 380 | break; 381 | } 382 | case RSP_VADDC: 383 | case RSP_VSUBC: 384 | { 385 | for (i=0; i < 8; i++) 386 | { 387 | int sel = VEC_EL_2(EL, i); 388 | RSP_SET_VEC_I(info->used, VS1REG, i); 389 | RSP_SET_VEC_I(info->used, VS2REG, sel); 390 | RSP_SET_VEC_I(info->set, VDREG, i); 391 | RSP_SET_ACCU_I(info->set, i, 2); 392 | } 393 | RSP_SET_FLAG_I(info->set, 0); 394 | break; 395 | } 396 | case RSP_VSAW: 397 | switch (EL) 398 | { 399 | case 0x08: // VSAWH 400 | { 401 | for (i=0; i < 8; i++) 402 | { 403 | RSP_SET_VEC_I(info->set, VDREG, i); 404 | RSP_SET_ACCU_I(info->used, i, 8); 405 | } 406 | break; 407 | } 408 | case 0x09: // VSAWM 409 | { 410 | for (i=0; i < 8; i++) 411 | { 412 | RSP_SET_VEC_I(info->set, VDREG, i); 413 | RSP_SET_ACCU_I(info->used, i, 4); 414 | } 415 | break; 416 | } 417 | case 0x0a: // VSAWL 418 | { 419 | for (i=0; i < 8; i++) 420 | { 421 | RSP_SET_VEC_I(info->set, VDREG, i); 422 | RSP_SET_ACCU_I(info->used, i, 2); 423 | } 424 | break; 425 | } 426 | default: 427 | log(M64MSG_ERROR, "RSP: VSAW: el = %d\n", EL); 428 | } 429 | break; 430 | case RSP_VLT: 431 | { 432 | for (i=0; i < 8; i++) 433 | { 434 | int sel = VEC_EL_2(EL, i); 435 | RSP_SET_VEC_I(info->used, VS1REG, i); 436 | RSP_SET_VEC_I(info->used, VS2REG, sel); 437 | RSP_SET_VEC_I(info->set, VDREG, i); 438 | RSP_SET_ACCU_I(info->set, i, 2); 439 | } 440 | RSP_SET_FLAG_I(info->set, 0); 441 | RSP_SET_FLAG_I(info->set, 1); 442 | break; 443 | } 444 | case RSP_VEQ: 445 | case RSP_VNE: 446 | case RSP_VGE: 447 | { 448 | for (i=0; i < 8; i++) 449 | { 450 | int sel = VEC_EL_2(EL, i); 451 | RSP_SET_VEC_I(info->used, VS1REG, i); 452 | RSP_SET_VEC_I(info->used, VS2REG, sel); 453 | RSP_SET_VEC_I(info->set, VDREG, i); 454 | RSP_SET_ACCU_I(info->set, i, 2); 455 | } 456 | RSP_SET_FLAG_I(info->used, 0); 457 | RSP_SET_FLAG_I(info->set, 0); 458 | RSP_SET_FLAG_I(info->set, 1); 459 | break; 460 | } 461 | case RSP_VCL: 462 | { 463 | for (i=0; i < 8; i++) 464 | { 465 | int sel = VEC_EL_2(EL, i); 466 | RSP_SET_VEC_I(info->used, VS1REG, i); 467 | RSP_SET_VEC_I(info->used, VS2REG, sel); 468 | RSP_SET_VEC_I(info->set, VDREG, i); 469 | RSP_SET_ACCU_I(info->set, i, 2); 470 | } 471 | RSP_SET_FLAG_I(info->used, 0); 472 | RSP_SET_FLAG_I(info->used, 1); 473 | RSP_SET_FLAG_I(info->set, 0); 474 | RSP_SET_FLAG_I(info->set, 1); 475 | RSP_SET_FLAG_I(info->set, 2); 476 | break; 477 | } 478 | case RSP_VCH: 479 | case RSP_VCR: 480 | { 481 | for (i=0; i < 8; i++) 482 | { 483 | int sel = VEC_EL_2(EL, i); 484 | RSP_SET_VEC_I(info->used, VS1REG, i); 485 | RSP_SET_VEC_I(info->used, VS2REG, sel); 486 | RSP_SET_VEC_I(info->set, VDREG, i); 487 | RSP_SET_ACCU_I(info->set, i, 2); 488 | } 489 | RSP_SET_FLAG_I(info->set, 0); 490 | RSP_SET_FLAG_I(info->set, 1); 491 | RSP_SET_FLAG_I(info->set, 2); 492 | break; 493 | } 494 | case RSP_VMRG: 495 | { 496 | for (i=0; i < 8; i++) 497 | { 498 | int sel = VEC_EL_2(EL, i); 499 | RSP_SET_VEC_I(info->used, VS1REG, i); 500 | RSP_SET_VEC_I(info->used, VS2REG, sel); 501 | RSP_SET_VEC_I(info->set, VDREG, i); 502 | RSP_SET_ACCU_I(info->set, i, 2); 503 | } 504 | RSP_SET_FLAG_I(info->used, 1); 505 | break; 506 | } 507 | case RSP_VAND: 508 | case RSP_VNAND: 509 | case RSP_VOR: 510 | case RSP_VNOR: 511 | case RSP_VXOR: 512 | case RSP_VNXOR: 513 | { 514 | for (i=0; i < 8; i++) 515 | { 516 | int sel = VEC_EL_2(EL, i); 517 | RSP_SET_VEC_I(info->used, VS1REG, i); 518 | RSP_SET_VEC_I(info->used, VS2REG, sel); 519 | RSP_SET_VEC_I(info->set, VDREG, i); 520 | RSP_SET_ACCU_I(info->set, i, 2); 521 | } 522 | break; 523 | } 524 | case RSP_VRCP: 525 | case RSP_VRCPL: 526 | case RSP_VRCPH: 527 | case RSP_VRSQL: 528 | case RSP_VRSQH: 529 | { 530 | int del = (VS1REG & 7); 531 | int sel = VEC_EL_2(EL, del); 532 | 533 | RSP_SET_VEC_I(info->used, VS2REG, sel); 534 | 535 | for (i=0; i < 8; i++) 536 | { 537 | int element = VEC_EL_2(EL, i); 538 | RSP_SET_VEC_I(info->used, VS2REG, element); 539 | RSP_SET_ACCU_I(info->set, i, 2); 540 | } 541 | 542 | RSP_SET_VEC_I(info->set, VDREG, del); 543 | break; 544 | } 545 | case RSP_VMOV: 546 | { 547 | int element = VS1REG & 7; 548 | RSP_SET_VEC_I(info->used, VS2REG, VEC_EL_2(EL, 7-element)); 549 | RSP_SET_VEC_I(info->set, VDREG, element); 550 | break; 551 | } 552 | 553 | default: 554 | { 555 | // char string[200]; 556 | // rsp_dasm_one(string, 0x800, op); 557 | // if (strcmp(string, "???")) { 558 | // printf("%s\n", string); 559 | // printf("unimplemented opcode\n"); 560 | // } 561 | break; 562 | } 563 | } 564 | } 565 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /src/rsp_recomp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "m64p_plugin.h" 27 | #include "m64p_types.h" 28 | #include "rsp.h" 29 | #include "rsp_recomp.h" 30 | 31 | #define GENDEBUG 32 | 33 | struct gen_t { 34 | UINT32 crc; 35 | int lbc; 36 | rsp_bc_t * bc; 37 | #ifdef GENDEBUG 38 | char name[32]; 39 | #endif 40 | }; 41 | 42 | struct opinfo_t { 43 | int visit, labeled; 44 | int label; 45 | 46 | unsigned int nbgen; 47 | unsigned int szgen; 48 | gen_t * gentable; 49 | gen_t * curgen; 50 | }; 51 | 52 | struct branch_t { 53 | int start, end; 54 | }; 55 | 56 | static int curvisit; 57 | static opinfo_t opinfo[0x1000/4]; 58 | static int jumps[0x1000]; 59 | static unsigned int nb_branches; 60 | static branch_t branches[256]; 61 | static unsigned int nb_labels; 62 | static int labels[256]; 63 | 64 | #define OPI(pc) opinfo[(pc)>>2] 65 | /*inline*/ void SETLABEL(int pc) { 66 | //printf("%x\n", pc); 67 | //pc &= 0xfff; 68 | assert(pc >= 0 && pc < 0x1000); 69 | if (OPI(pc).labeled != curvisit) { 70 | labels[nb_labels] = pc; 71 | OPI(pc).label = nb_labels++; 72 | assert(nb_labels < sizeof(labels)/sizeof(labels[0])); 73 | OPI(pc).labeled = curvisit; 74 | } 75 | } 76 | 77 | #define ABS(addr) (((addr) << 2) & 0xfff) 78 | #define REL(offset) ((pc + ((offset) << 2)) & 0xfff) 79 | 80 | static UINT32 prep_gen(int pc, UINT32 crc, int & len) 81 | { 82 | UINT32 op; 83 | int br = 0; 84 | 85 | branches[nb_branches].start = pc; 86 | 87 | while ( !br ) 88 | { 89 | if (OPI(pc).visit == curvisit) { 90 | SETLABEL((pc)&0xfff); 91 | SETLABEL((pc+4)&0xfff); 92 | break; 93 | } 94 | 95 | OPI(pc).visit = curvisit; 96 | 97 | op = ROPCODE(pc); 98 | crc = ((crc<<1)|(crc>>31))^op^pc; 99 | pc = (pc+4)&0xfff; 100 | len++; 101 | 102 | switch (op >> 26) 103 | { 104 | case 0x00: /* SPECIAL */ 105 | { 106 | switch (op & 0x3f) 107 | { 108 | case 0x08: /* JR */ 109 | br = 1; 110 | break; 111 | case 0x09: /* JALR */ 112 | //br = 1; 113 | break; 114 | case 0x0d: /* BREAK */ 115 | br = 1; 116 | break; 117 | } 118 | break; 119 | } 120 | 121 | case 0x01: /* REGIMM */ 122 | { 123 | switch (RTREG) 124 | { 125 | case 0x00: /* BLTZ */ 126 | case 0x01: /* BGEZ */ 127 | SETLABEL(REL(SIMM16)); 128 | break; 129 | case 0x11: /* BGEZAL */ 130 | //br = 1; 131 | break; 132 | } 133 | break; 134 | } 135 | 136 | case 0x02: /* J */ 137 | SETLABEL(ABS(UIMM26)); 138 | br = 1; 139 | break; 140 | case 0x04: /* BEQ */ 141 | case 0x05: /* BNE */ 142 | case 0x06: /* BLEZ */ 143 | case 0x07: /* BGTZ */ 144 | SETLABEL(REL(SIMM16)); 145 | break; 146 | case 0x03: /* JAL */ 147 | //SETLABEL(ABS(UIMM26)); 148 | //br = 1; 149 | break; 150 | } 151 | 152 | } 153 | 154 | branches[nb_branches++].end = pc; 155 | assert(nb_branches < sizeof(branches)/sizeof(branches[0])); 156 | 157 | return crc; 158 | } 159 | 160 | static void rsp_gen(int pc) 161 | { 162 | unsigned int i; 163 | 164 | curvisit++; 165 | if (!curvisit) { 166 | // we looped, reset all visit counters 167 | for (i=0; i<0x1000/4; i++) { 168 | opinfo[i].visit = 0; 169 | opinfo[i].labeled = 0; 170 | } 171 | curvisit++; 172 | } 173 | 174 | nb_branches = 0; 175 | nb_labels = 0; 176 | 177 | int len = 0; 178 | UINT32 crc = prep_gen(pc, 0, len); 179 | 180 | for (i=0; igentable) { 187 | for (i=0; inbgen; i++) 188 | if (opi->gentable[i].crc == crc) { 189 | opi->curgen = opi->gentable + i; 190 | return; 191 | } 192 | } 193 | if (opi->nbgen >= opi->szgen) { 194 | if (opi->szgen) 195 | opi->szgen *= 2; 196 | else 197 | opi->szgen = 4; 198 | opi->gentable = (gen_t *) realloc(opi->gentable, sizeof(gen_t)*(opi->szgen)); 199 | } 200 | gen_t * gen; 201 | gen = opi->gentable + opi->nbgen++; 202 | gen->crc = crc; 203 | opi->curgen = gen; 204 | 205 | // convert to bytecode 206 | unsigned int lbc = 0; 207 | static rsp_bc_t bc[0x1000*2+10]; 208 | for (i=0; i>3)&0xffc; 300 | // char s[128]; 301 | // rsp_dasm_one(s, realpc, bc[i].op); 302 | // printf("%3x\t%s\n", realpc, s); 303 | // } 304 | switch (bc[i].op2) { 305 | case RSP_JUMPLOCAL: 306 | case RSP_CONDJUMPLOCAL: 307 | case RSP_LOOP: 308 | { 309 | // int pc; 310 | // for (pc = 0; pc>5)<<2) == bc[i].flags) 314 | // break; 315 | // assert(pc < lbc); 316 | // bc[i].flags = pc<<5; 317 | bc[i].flags = jumps[bc[i].flags]<<5; 318 | break; 319 | } 320 | } 321 | } 322 | 323 | gen->lbc = lbc; 324 | gen->bc = (rsp_bc_t *) malloc(sizeof(rsp_bc_t)*lbc); 325 | memcpy(gen->bc, bc, sizeof(rsp_bc_t)*lbc); 326 | } 327 | 328 | void rsp_invalidate(int begin, int len) 329 | { 330 | //printf("invalidate %x %x\n", begin, len); 331 | begin = 0; len = 0x1000; 332 | assert(begin+len<=0x1000); 333 | while (len > 0) { 334 | OPI(begin).curgen = 0; 335 | begin += 4; 336 | len -= 4; 337 | } 338 | rsp.inval_gen = 1; 339 | } 340 | 341 | inline void rsp_execute_one(RSP_REGS & rsp, const UINT32 op) 342 | { 343 | switch (op >> 26) 344 | { 345 | case 0x12: /* COP2 */ 346 | { 347 | handle_vector_ops(op); 348 | break; 349 | } 350 | 351 | case 0x32: /* LWC2 */ handle_lwc2(op); break; 352 | case 0x3a: /* SWC2 */ handle_swc2(op); break; 353 | 354 | default: 355 | { 356 | unimplemented_opcode(op); 357 | break; 358 | } 359 | } 360 | } 361 | 362 | static int cond; 363 | static int run(RSP_REGS & rsp, gen_t * gen) 364 | { 365 | int pc = 0; 366 | 367 | cond = 0; 368 | for ( ; ; ) { 369 | const rsp_bc_t & bc = gen->bc[pc]; 370 | const UINT32 op = bc.op; 371 | const int op2 = bc.op2; 372 | 373 | // if (op2 < RSP_CONTROL_OFFS) { 374 | // int realpc = (bc.flags>>3)&0xffc; 375 | // char s[128]; 376 | // rsp_dasm_one(s, realpc, op); 377 | // fprintf(stderr, "%3x\t%s\n", realpc, s); 378 | // } 379 | 380 | pc++; 381 | switch (op2) { 382 | case RSP_LOOP: 383 | pc = bc.flags>>5; 384 | break; 385 | case RSP_JUMPLOCAL: 386 | case RSP_CONDJUMPLOCAL: 387 | if (cond) { 388 | pc = bc.flags>>5; 389 | cond = 0; 390 | } 391 | break; 392 | case RSP_JUMP: 393 | case RSP_CONDJUMP: 394 | if (cond) { 395 | return 0; 396 | } 397 | break; 398 | 399 | #define _LINK(l) rsp.r[l] = ((bc.flags >>3)+8)&0xffc 400 | #define _JUMP_PC(a) { cond=1; rsp.nextpc = ((a) & 0xfff); } 401 | #define _JUMP_PC_L(a, l) { _LINK(l); _JUMP_PC(a); } 402 | #define _JUMP_REL(a) _JUMP_PC(((bc.flags >>3)+4+(a<<2))&0xffc) 403 | #define _JUMP_REL_L(a, l) _JUMP_PC_L(((bc.flags >>3)+4+(a<<2))&0xffc, l) 404 | 405 | case RSP_SLL: if (RDREG) RDVAL = (UINT32)RTVAL << SHIFT; break; 406 | case RSP_SRL: if (RDREG) RDVAL = (UINT32)RTVAL >> SHIFT; break; 407 | case RSP_SRA: if (RDREG) RDVAL = (INT32)RTVAL >> SHIFT; break; 408 | case RSP_SLLV: if (RDREG) RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); break; 409 | case RSP_SRLV: if (RDREG) RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); break; 410 | case RSP_SRAV: if (RDREG) RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); break; 411 | case RSP_JR: _JUMP_PC(RSVAL); break; 412 | case RSP_JALR: _JUMP_PC_L(RSVAL, RDREG); break; 413 | case RSP_BREAK: 414 | { 415 | *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE ); 416 | if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { 417 | *z64_rspinfo.MI_INTR_REG |= 1; 418 | z64_rspinfo.CheckInterrupts(); 419 | } 420 | return 1; 421 | } 422 | case RSP_ADD: if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; 423 | case RSP_ADDU: if (RDREG) RDVAL = (INT32)(RSVAL + RTVAL); break; 424 | case RSP_SUB: if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break; 425 | case RSP_SUBU: if (RDREG) RDVAL = (INT32)(RSVAL - RTVAL); break; 426 | case RSP_AND: if (RDREG) RDVAL = RSVAL & RTVAL; break; 427 | case RSP_OR: if (RDREG) RDVAL = RSVAL | RTVAL; break; 428 | case RSP_XOR: if (RDREG) RDVAL = RSVAL ^ RTVAL; break; 429 | case RSP_NOR: if (RDREG) RDVAL = ~(RSVAL | RTVAL); break; 430 | case RSP_SLT: if (RDREG) RDVAL = (INT32)RSVAL < (INT32)RTVAL; break; 431 | case RSP_SLTU: if (RDREG) RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; break; 432 | case RSP_BLTZ: if ((INT32)(RSVAL) < 0) cond = 1; break; 433 | case RSP_BGEZ: if ((INT32)(RSVAL) >= 0) cond = 1; break; 434 | case RSP_BGEZAL: _LINK(31); if ((INT32)(RSVAL) >= 0) _JUMP_REL(SIMM16); break; 435 | case RSP_J: cond = 1; break; 436 | case RSP_JAL: _JUMP_PC_L(UIMM26<<2, 31); break; 437 | case RSP_BEQ: if (RSVAL == RTVAL) cond = 1; break; 438 | case RSP_BNE: if (RSVAL != RTVAL) cond = 1; break; 439 | case RSP_BLEZ: if ((INT32)RSVAL <= 0) cond = 1; break; 440 | case RSP_BGTZ: if ((INT32)RSVAL > 0) cond = 1; break; 441 | case RSP_ADDI: if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break; 442 | case RSP_ADDIU: if (RTREG) RTVAL = (INT32)(RSVAL + SIMM16); break; 443 | case RSP_SLTI: if (RTREG) RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); break; 444 | case RSP_SLTIU: if (RTREG) RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); break; 445 | case RSP_ANDI: if (RTREG) RTVAL = RSVAL & UIMM16; break; 446 | case RSP_ORI: if (RTREG) RTVAL = RSVAL | UIMM16; break; 447 | case RSP_XORI: if (RTREG) RTVAL = RSVAL ^ UIMM16; break; 448 | case RSP_LUI: if (RTREG) RTVAL = UIMM16 << 16; break; 449 | 450 | case RSP_COP0: 451 | { 452 | switch ((op >> 21) & 0x1f) 453 | { 454 | case 0x00: /* MFC0 */ 455 | if (RTREG) 456 | RTVAL = get_cop0_reg(RDREG); 457 | break; 458 | case 0x04: /* MTC0 */ 459 | set_cop0_reg(RDREG, RTVAL); 460 | if (rsp.inval_gen) { 461 | rsp.inval_gen = 0; 462 | sp_pc = ((bc.flags >>3) + 4)&0xffc; 463 | return 2; 464 | } 465 | break; 466 | default: 467 | log(M64MSG_WARNING, "unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op); 468 | break; 469 | } 470 | break; 471 | } 472 | 473 | case RSP_MFC2: 474 | { 475 | // 31 25 20 15 10 6 0 476 | // --------------------------------------------------- 477 | // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | 478 | // --------------------------------------------------- 479 | // 480 | 481 | int el = (op >> 7) & 0xf; 482 | UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf); 483 | UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf); 484 | if (RTREG) RTVAL = (INT32)(INT16)((b1 << 8) | (b2)); 485 | break; 486 | } 487 | case RSP_CFC2: 488 | { 489 | // 31 25 20 15 10 0 490 | // ------------------------------------------------ 491 | // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | 492 | // ------------------------------------------------ 493 | // 494 | 495 | // VP to sign extend or to not sign extend ? 496 | //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG]; 497 | if (RTREG) RTVAL = rsp.flag[RDREG]; 498 | break; 499 | } 500 | case RSP_MTC2: 501 | { 502 | // 31 25 20 15 10 6 0 503 | // --------------------------------------------------- 504 | // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | 505 | // --------------------------------------------------- 506 | // 507 | 508 | int el = (op >> 7) & 0xf; 509 | VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff; 510 | VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff; 511 | break; 512 | } 513 | case RSP_CTC2: 514 | { 515 | // 31 25 20 15 10 0 516 | // ------------------------------------------------ 517 | // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 | 518 | // ------------------------------------------------ 519 | // 520 | 521 | rsp.flag[RDREG] = RTVAL & 0xffff; 522 | break; 523 | } 524 | case RSP_LB: if (RTREG) RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); break; 525 | case RSP_LH: if (RTREG) RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); break; 526 | case RSP_LW: if (RTREG) RTVAL = READ32(RSVAL + SIMM16); break; 527 | case RSP_LBU: if (RTREG) RTVAL = (UINT8)READ8(RSVAL + SIMM16); break; 528 | case RSP_LHU: if (RTREG) RTVAL = (UINT16)READ16(RSVAL + SIMM16); break; 529 | case RSP_SB: WRITE8(RSVAL + SIMM16, RTVAL); break; 530 | case RSP_SH: WRITE16(RSVAL + SIMM16, RTVAL); break; 531 | case RSP_SW: WRITE32(RSVAL + SIMM16, RTVAL); break; 532 | 533 | default: 534 | switch (op >> 26) 535 | { 536 | case 0x12: /* COP2 */ 537 | handle_vector_ops(op); 538 | break; 539 | case 0x32: /* LWC2 */ 540 | handle_lwc2(op); 541 | break; 542 | case 0x3a: /* SWC2 */ 543 | handle_swc2(op); 544 | break; 545 | } 546 | } 547 | } 548 | } 549 | 550 | int rsp_gen_cache_hit; 551 | int rsp_gen_cache_miss; 552 | int rsp_jump(int pc) 553 | { 554 | pc &= 0xfff; 555 | sp_pc = pc; 556 | rsp.nextpc = ~0; 557 | opinfo_t * opi = &OPI(pc); 558 | gen_t * gen = opi->curgen; 559 | rsp_gen_cache_hit++; 560 | if (!gen) { 561 | rsp_gen_cache_miss++; 562 | rsp_gen(pc); 563 | } 564 | gen = opi->curgen; 565 | //fprintf(stderr, "rsp_jump %x (%s)\n", pc, gen->name); 566 | 567 | int res = run(rsp, gen); 568 | 569 | //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); 570 | if (rsp.nextpc != ~0U) 571 | { 572 | sp_pc = (rsp.nextpc & 0xfff); 573 | rsp.nextpc = ~0U; 574 | } 575 | else 576 | { 577 | //sp_pc = ((sp_pc+4)&0xfff); 578 | } 579 | return res; 580 | } 581 | -------------------------------------------------------------------------------- /src/rsp_dasm.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | /* 23 | Nintendo/SGI RSP Disassembler 24 | 25 | Written by Ville Linde 26 | */ 27 | 28 | //#include "z64.h" 29 | #include 30 | #include 31 | 32 | #include "rsp.h" 33 | #include "z64.h" 34 | 35 | #define DASMFLAG_SUPPORTED 0x80000000 /* are disassembly flags supported? */ 36 | #define DASMFLAG_STEP_OUT 0x40000000 /* this instruction should be the end of a step out sequence */ 37 | #define DASMFLAG_STEP_OVER 0x20000000 /* this instruction should be stepped over by setting a breakpoint afterwards */ 38 | #define DASMFLAG_OVERINSTMASK 0x18000000 /* number of extra instructions to skip when stepping over */ 39 | #define DASMFLAG_OVERINSTSHIFT 27 /* bits to shift after masking to get the value */ 40 | #define DASMFLAG_LENGTHMASK 0x0000ffff /* the low 16-bits contain the actual length */ 41 | #define DASMFLAG_STEP_OVER_EXTRA(x) ((x) << DASMFLAG_OVERINSTSHIFT) 42 | 43 | #if defined(__GNUC__) 44 | #define ATTR_FMT(fmtpos, attrpos) __attribute__ ((format (printf, fmtpos, attrpos))) 45 | #else 46 | #define ATTR_FMT(fmtpos, attrpos) 47 | #endif 48 | 49 | static const char *reg[32] = 50 | { 51 | "0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 52 | "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 53 | "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 54 | "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" 55 | }; 56 | 57 | static const char *vreg[32] = 58 | { 59 | " v0", " v1", " v2", " v3", " v4", " v5", " v6", " v7", 60 | " v8", " v9", "v10", "v11", "v12", "v13", "v14", "v15", 61 | "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", 62 | "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" 63 | }; 64 | 65 | static const char *cop0_regs[32] = 66 | { 67 | "SP_MEM_ADDR", "SP_DRAM_ADDR", "SP_RD_LEN", "SP_WR_LEN", 68 | "SP_STATUS", "SP_DMA_FULL", "SP_DMA_BUSY", "SP_SEMAPHORE", 69 | "DPC_START", "DPC_END", "DPC_CURRENT", "DPC_STATUS", 70 | "DPC_CLOCK", "DPC_BUFBUSY", "DPC_PIPEBUSY", "DPC_TMEM", 71 | "???", "???", "???", "???", 72 | "???", "???", "???", "???", 73 | "???", "???", "???", "???", 74 | "???", "???", "???", "???" 75 | }; 76 | 77 | static const char *element[16] = 78 | { 79 | "", "[???]", "[00224466]", "[11335577]", "[00004444]", "[11115555]", "[22226666]", "[33337777]", 80 | "[00000000]", "[11111111]", "[22222222]", "[33333333]", "[44444444]", "[55555555]", "[66666666]", "[77777777]" 81 | }; 82 | 83 | static const char *element2[16] = 84 | { 85 | "01234567", "????????", "00224466", "11335577", "00004444", "11115555", "22226666", "33337777", 86 | "00000000", "11111111", "22222222", "33333333", "44444444", "55555555", "66666666", "77777777" 87 | }; 88 | 89 | #define INLINE inline 90 | INLINE char *signed_imm16(UINT32 op) 91 | { 92 | static char temp[10]; 93 | INT16 value = op & 0xffff; 94 | 95 | if (value < 0) 96 | { 97 | sprintf(temp, "-$%04x", -value); 98 | } 99 | else 100 | { 101 | sprintf(temp, "$%04x", value); 102 | } 103 | return temp; 104 | } 105 | 106 | 107 | static char *output; 108 | 109 | static void print(const char *fmt, ...) ATTR_FMT(1, 2); 110 | 111 | void print(const char *fmt, ...) 112 | { 113 | va_list vl; 114 | 115 | va_start(vl, fmt); 116 | output += vsprintf(output, fmt, vl); 117 | va_end(vl); 118 | } 119 | 120 | static void disasm_cop0(UINT32 op) 121 | { 122 | int rt = (op >> 16) & 31; 123 | int rd = (op >> 11) & 31; 124 | 125 | switch ((op >> 21) & 0x1f) 126 | { 127 | case 0x00: print("mfc0 %s, %s", reg[rt], cop0_regs[rd]); break; 128 | case 0x04: print("mtc0 %s, %s", reg[rt], cop0_regs[rd]); break; 129 | 130 | default: print("??? (COP0)"); break; 131 | } 132 | } 133 | 134 | static void disasm_cop2(UINT32 op) 135 | { 136 | int rt = (op >> 16) & 31; 137 | int rd = (op >> 11) & 31; 138 | int el = (op >> 21) & 0xf; 139 | int dest = (op >> 6) & 0x1f; 140 | int s1 = rd; 141 | int s2 = rt; 142 | 143 | switch ((op >> 21) & 0x1f) 144 | { 145 | case 0x00: print("mfc2 %s, %s[%d]", reg[rt], vreg[rd], dest); break; 146 | case 0x02: print("cfc2 %s, FLAG%d", reg[rt], rd); break; 147 | case 0x04: print("mtc2 %s, %s[%d]", reg[rt], vreg[rd], dest); break; 148 | case 0x06: print("ctc2 %s, FLAG%d", reg[rt], rd); break; 149 | 150 | case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: 151 | case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: 152 | { 153 | switch (op & 0x3f) 154 | { 155 | case 0x00: print("vmulf %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 156 | case 0x01: print("vmulu %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 157 | case 0x02: print("vrndp %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 158 | case 0x03: print("vmulq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 159 | case 0x04: print("vmudl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 160 | case 0x05: print("vmudm %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 161 | case 0x06: print("vmudn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 162 | case 0x07: print("vmudh %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 163 | case 0x08: print("vmacf %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 164 | case 0x09: print("vmacu %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 165 | case 0x0a: print("vrndn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 166 | case 0x0b: print("vmacq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 167 | case 0x0c: print("vmadl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 168 | case 0x0d: print("vmadm %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 169 | case 0x0e: print("vmadn %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 170 | case 0x0f: print("vmadh %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 171 | case 0x10: print("vadd %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 172 | case 0x11: print("vsub %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 173 | case 0x12: print("vsut???"); break; 174 | case 0x13: print("vabs %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 175 | case 0x14: print("vaddc %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 176 | case 0x15: print("vsubc %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 177 | 178 | case 0x1d: 179 | { 180 | switch (el) 181 | { 182 | case 8: print("vsaw %s, ACCUM_H", vreg[dest]); break; 183 | case 9: print("vsaw %s, ACCUM_M", vreg[dest]); break; 184 | case 10: print("vsaw %s, ACCUM_L", vreg[dest]); break; 185 | default: print("vsaw %s, ???", vreg[dest]); break; 186 | } 187 | break; 188 | } 189 | 190 | case 0x20: print("vlt %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 191 | case 0x21: print("veq %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 192 | case 0x22: print("vne %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 193 | case 0x23: print("vge %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 194 | case 0x24: print("vcl %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 195 | case 0x25: print("vch %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 196 | case 0x26: print("vcr %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 197 | case 0x27: print("vmrg %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 198 | case 0x28: print("vand %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 199 | case 0x29: print("vnand %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 200 | case 0x2a: print("vor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 201 | case 0x2b: print("vnor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 202 | case 0x2c: print("vxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 203 | case 0x2d: print("vnxor %s, %s, %s%s", vreg[dest], vreg[s1], vreg[s2], element[el]); break; 204 | case 0x30: print("vrcp %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; 205 | case 0x31: print("vrcpl %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; 206 | case 0x32: print("vrcph %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; 207 | case 0x33: print("vmov %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; 208 | case 0x34: print("vrsq %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; 209 | case 0x35: print("vrsql %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; 210 | case 0x36: print("vrsqh %s[%d], %s[%c]", vreg[dest], s1 & 7, vreg[s2], element2[el][7-(s1 & 7)]); break; 211 | case 0x37: print("vnop"); break; 212 | default: print("??? (VECTOR OP)"); break; 213 | } 214 | break; 215 | } 216 | 217 | default: print("??? (COP2)"); break; 218 | } 219 | } 220 | 221 | static void disasm_lwc2(UINT32 op) 222 | { 223 | int dest = (op >> 16) & 0x1f; 224 | int base = (op >> 21) & 0x1f; 225 | int del = (op >> 7) & 0xf; 226 | int offset = (op & 0x7f); 227 | if (offset & 0x40) 228 | offset |= 0xffffff80; 229 | 230 | switch ((op >> 11) & 0x1f) 231 | { 232 | case 0x00: print("lbv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 1), reg[base]); break; 233 | case 0x01: print("lsv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 2), reg[base]); break; 234 | case 0x02: print("llv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 4), reg[base]); break; 235 | case 0x03: print("ldv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; 236 | case 0x04: print("lqv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 237 | case 0x05: print("lrv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 238 | case 0x06: print("lpv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; 239 | case 0x07: print("luv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; 240 | case 0x08: print("lhv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 241 | case 0x09: print("lfv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 242 | case 0x0a: print("lwv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 243 | case 0x0b: print("ltv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 244 | default: print("??? (LWC2)"); break; 245 | } 246 | } 247 | 248 | static void disasm_swc2(UINT32 op) 249 | { 250 | int dest = (op >> 16) & 0x1f; 251 | int base = (op >> 21) & 0x1f; 252 | int del = (op >> 7) & 0xf; 253 | int offset = (op & 0x7f); 254 | if (offset & 0x40) 255 | offset |= 0xffffff80; 256 | 257 | switch ((op >> 11) & 0x1f) 258 | { 259 | case 0x00: print("sbv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 1), reg[base]); break; 260 | case 0x01: print("ssv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 2), reg[base]); break; 261 | case 0x02: print("slv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 4), reg[base]); break; 262 | case 0x03: print("sdv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; 263 | case 0x04: print("sqv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 264 | case 0x05: print("srv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 265 | case 0x06: print("spv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; 266 | case 0x07: print("suv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 8), reg[base]); break; 267 | case 0x08: print("shv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 268 | case 0x09: print("sfv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 269 | case 0x0a: print("swv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 270 | case 0x0b: print("stv %s[%d], %s(%s)", vreg[dest], del, signed_imm16(offset * 16), reg[base]); break; 271 | default: print("??? (SWC2)"); break; 272 | } 273 | } 274 | 275 | offs_t rsp_dasm_one(char *buffer, offs_t pc, UINT32 op) 276 | { 277 | int rs = (op >> 21) & 31; 278 | int rt = (op >> 16) & 31; 279 | int rd = (op >> 11) & 31; 280 | int shift = (op >> 6) & 31; 281 | UINT32 flags = 0; 282 | 283 | output = buffer; 284 | 285 | switch (op >> 26) 286 | { 287 | case 0x00: // SPECIAL 288 | { 289 | switch (op & 0x3f) 290 | { 291 | case 0x00: 292 | { 293 | if (op == 0) 294 | { 295 | print("nop"); 296 | } 297 | else 298 | { 299 | print("sll %s, %s, %d", reg[rd], reg[rt], shift); 300 | } 301 | break; 302 | } 303 | case 0x02: print("srl %s, %s, %d", reg[rd], reg[rt], shift); break; 304 | case 0x03: print("sra %s, %s, %d", reg[rd], reg[rt], shift); break; 305 | case 0x04: print("sllv %s, %s, %s", reg[rd], reg[rt], reg[rs]); break; 306 | case 0x06: print("srlv %s, %s, %s", reg[rd], reg[rt], reg[rs]); break; 307 | case 0x07: print("srav %s, %s, %s", reg[rd], reg[rt], reg[rs]); break; 308 | case 0x08: print("jr %s", reg[rs]); if (rs == 31) flags = DASMFLAG_STEP_OUT; break; 309 | case 0x09: 310 | { 311 | if (rd == 31) 312 | { 313 | print("jalr %s", reg[rs]); 314 | } 315 | else 316 | { 317 | print("jalr %s, %s", reg[rs], reg[rd]); 318 | } 319 | flags = DASMFLAG_STEP_OVER | DASMFLAG_STEP_OVER_EXTRA(1); 320 | break; 321 | } 322 | case 0x0d: print("break"); flags = DASMFLAG_STEP_OVER; break; 323 | case 0x20: print("add %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 324 | case 0x21: print("addu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 325 | case 0x22: print("sub %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 326 | case 0x23: print("subu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 327 | case 0x24: print("and %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 328 | case 0x25: print("or %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 329 | case 0x26: print("xor %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 330 | case 0x27: print("nor %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 331 | case 0x2a: print("slt %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 332 | case 0x2b: print("sltu %s, %s, %s", reg[rd], reg[rs], reg[rt]); break; 333 | 334 | default: print("???"); break; 335 | } 336 | break; 337 | } 338 | 339 | case 0x01: // REGIMM 340 | { 341 | switch ((op >> 16) & 0x1f) 342 | { 343 | case 0x00: print("bltz %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break; 344 | case 0x01: print("bgez %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break; 345 | case 0x10: print("bltzal %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break; 346 | case 0x11: print("bgezal %s, $%08X", reg[rs], pc + 4 + ((INT16)op << 2)); break; 347 | 348 | default: print("???"); break; 349 | } 350 | break; 351 | } 352 | 353 | case 0x02: print("j $%08X", (op & 0x03ffffff) << 2); break; 354 | case 0x03: print("jal $%08X", (op & 0x03ffffff) << 2); break; 355 | case 0x04: print("beq %s, %s, $%08X", reg[rs], reg[rt], pc + 4 + ((INT16)(op) << 2)); break; 356 | case 0x05: print("bne %s, %s, $%08X", reg[rs], reg[rt], pc + 4 + ((INT16)(op) << 2)); break; 357 | case 0x06: print("blez %s, $%08X", reg[rs], pc + 4 + ((INT16)(op) << 2)); break; 358 | case 0x07: print("bgtz %s, $%08X", reg[rs], pc + 4 + ((INT16)(op) << 2)); break; 359 | case 0x08: print("addi %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break; 360 | case 0x09: print("addiu %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break; 361 | case 0x0a: print("slti %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break; 362 | case 0x0b: print("sltiu %s, %s, %s", reg[rt], reg[rs], signed_imm16(op)); break; 363 | case 0x0c: print("andi %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break; 364 | case 0x0d: print("ori %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break; 365 | case 0x0e: print("xori %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break; 366 | case 0x0f: print("lui %s, %s, $%04X", reg[rt], reg[rs], (UINT16)(op)); break; 367 | 368 | case 0x10: disasm_cop0(op); break; 369 | case 0x12: disasm_cop2(op); break; 370 | 371 | case 0x20: print("lb %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; 372 | case 0x21: print("lh %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; 373 | case 0x23: print("lw %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; 374 | case 0x24: print("lbu %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; 375 | case 0x25: print("lhu %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; 376 | case 0x28: print("sb %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; 377 | case 0x29: print("sh %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; 378 | case 0x2b: print("sw %s, %s(%s)", reg[rt], signed_imm16(op), reg[rs]); break; 379 | 380 | case 0x32: disasm_lwc2(op); break; 381 | case 0x3a: disasm_swc2(op); break; 382 | 383 | default: print("???"); break; 384 | } 385 | 386 | return 4 | flags | DASMFLAG_SUPPORTED; 387 | } 388 | -------------------------------------------------------------------------------- /src/rsp_gen.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * z64 3 | * 4 | * Copyright (C) 2007 ziggy 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | **/ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "rsp.h" 29 | 30 | #define GENDEBUG 31 | 32 | typedef int (* gen_f)(RSP_REGS & rsp); 33 | 34 | struct gen_t { 35 | UINT32 crc; 36 | void * lib; 37 | gen_f f; 38 | #ifdef GENDEBUG 39 | char name[32]; 40 | #endif 41 | }; 42 | 43 | struct opinfo_t { 44 | int visit, labeled; 45 | int label; 46 | 47 | int nbgen; 48 | int szgen; 49 | gen_t * gentable; 50 | gen_t * curgen; 51 | }; 52 | 53 | struct branch_t { 54 | int start, end; 55 | }; 56 | 57 | static int curvisit; 58 | static opinfo_t opinfo[0x1000/4]; 59 | static int nb_branches; 60 | static branch_t branches[256]; 61 | static int nb_labels; 62 | static int labels[256]; 63 | 64 | #define OPI(pc) opinfo[(pc)>>2] 65 | /*inline*/ void SETLABEL(int pc) { 66 | //printf("%x\n", pc); 67 | //pc &= 0xfff; 68 | assert(pc >= 0 && pc < 0x1000); 69 | if (OPI(pc).labeled != curvisit) { 70 | labels[nb_labels] = pc; 71 | OPI(pc).label = nb_labels++; 72 | assert(nb_labels < sizeof(labels)/sizeof(labels[0])); 73 | OPI(pc).labeled = curvisit; 74 | } 75 | } 76 | 77 | #define ABS(addr) (((addr) << 2) & 0xfff) 78 | #define REL(offset) ((pc + ((offset) << 2)) & 0xfff) 79 | 80 | static UINT32 prep_gen(int pc, UINT32 crc, int & len) 81 | { 82 | UINT32 op; 83 | int br = 0; 84 | 85 | branches[nb_branches].start = pc; 86 | 87 | while ( !br ) 88 | { 89 | if (OPI(pc).visit == curvisit) { 90 | SETLABEL((pc)&0xfff); 91 | SETLABEL((pc+4)&0xfff); 92 | break; 93 | } 94 | 95 | OPI(pc).visit = curvisit; 96 | 97 | op = ROPCODE(pc); 98 | crc = ((crc<<1)|(crc>>31))^op^pc; 99 | pc = (pc+4)&0xfff; 100 | len++; 101 | 102 | switch (op >> 26) 103 | { 104 | case 0x00: /* SPECIAL */ 105 | { 106 | switch (op & 0x3f) 107 | { 108 | case 0x08: /* JR */ 109 | br = 1; 110 | break; 111 | case 0x09: /* JALR */ 112 | //br = 1; 113 | break; 114 | case 0x0d: /* BREAK */ 115 | br = 1; 116 | break; 117 | } 118 | break; 119 | } 120 | 121 | case 0x01: /* REGIMM */ 122 | { 123 | switch (RTREG) 124 | { 125 | case 0x00: /* BLTZ */ 126 | case 0x01: /* BGEZ */ 127 | SETLABEL(REL(SIMM16)); 128 | break; 129 | case 0x11: /* BGEZAL */ 130 | //br = 1; 131 | break; 132 | } 133 | break; 134 | } 135 | 136 | case 0x02: /* J */ 137 | SETLABEL(ABS(UIMM26)); 138 | br = 1; 139 | break; 140 | case 0x04: /* BEQ */ 141 | case 0x05: /* BNE */ 142 | case 0x06: /* BLEZ */ 143 | case 0x07: /* BGTZ */ 144 | SETLABEL(REL(SIMM16)); 145 | break; 146 | case 0x03: /* JAL */ 147 | //SETLABEL(ABS(UIMM26)); 148 | //br = 1; 149 | break; 150 | } 151 | 152 | } 153 | 154 | branches[nb_branches++].end = pc; 155 | assert(nb_branches < sizeof(branches)/sizeof(branches[0])); 156 | 157 | return crc; 158 | } 159 | 160 | static char tmps[1024]; 161 | static char * delayed; 162 | static int has_cond; 163 | 164 | #define COND \ 165 | has_cond = 1, fprintf 166 | 167 | #define NOCOND() \ 168 | if (cont && OPI((pc+4)&0xfff).labeled == curvisit) { \ 169 | COND(fp, "cond = 1; \n"); \ 170 | } else \ 171 | has_cond = 0 172 | 173 | 174 | static void D_JUMP_ABS(UINT32 addr) 175 | { 176 | int a = addr&0xfff; 177 | 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); 178 | delayed = tmps; 179 | } 180 | 181 | static void D_JUMP_REL(int pc, int offset) 182 | { 183 | D_JUMP_ABS(pc+4 + ((offset) << 2)); 184 | } 185 | 186 | static void D_JUMP() 187 | { 188 | sprintf(tmps, "%s { return 0; }", has_cond? "if (cond)":""); 189 | delayed = tmps; 190 | } 191 | 192 | static void D_JUMPL(int pc) 193 | { 194 | sprintf(tmps, 195 | "%s { \n" 196 | "%s" 197 | " int res;\n" 198 | " if (res = rsp_jump(rsp.nextpc)) return res; \n" 199 | " if (/*rsp.inval_gen || */sp_pc != 0x%x) return 0; \n" 200 | "}", has_cond? "if (cond)":"", has_cond?" cond=0; \n":"", (pc+8)&0xfff); 201 | delayed = tmps; 202 | has_cond = 1; 203 | } 204 | 205 | static void dogen(const char * s, UINT32 op, FILE * fp) 206 | { 207 | fprintf(fp, "#define op 0x%x\n%s\n#undef op\n", op, s); 208 | } 209 | 210 | #define GEN(s) dogen(s, op, fp) 211 | 212 | static void rsp_gen(int pc) 213 | { 214 | int i; 215 | const char * old_delayed; 216 | int oldbr, br; 217 | 218 | curvisit++; 219 | if (!curvisit) { 220 | // we looped, reset all visit counters 221 | for (i=0; i<0x1000/4; i++) { 222 | opinfo[i].visit = 0; 223 | opinfo[i].labeled = 0; 224 | } 225 | curvisit++; 226 | } 227 | 228 | nb_branches = 0; 229 | nb_labels = 0; 230 | 231 | int len = 0; 232 | UINT32 crc = prep_gen(pc, 0, len); 233 | 234 | for (i=0; igentable) { 247 | for (i=0; inbgen; i++) 248 | if (opi->gentable[i].crc == crc) { 249 | opi->curgen = opi->gentable + i; 250 | return; 251 | } 252 | } 253 | if (opi->nbgen >= opi->szgen) { 254 | if (opi->szgen) 255 | opi->szgen *= 2; 256 | else 257 | opi->szgen = 4; 258 | opi->gentable = (gen_t *) realloc(opi->gentable, sizeof(gen_t)*(opi->szgen)); 259 | } 260 | gen_t * gen; 261 | gen = opi->gentable + opi->nbgen++; 262 | opi->curgen = gen; 263 | 264 | #ifdef GENDEBUG 265 | strcpy(gen->name, lib); 266 | #endif 267 | 268 | gen->crc = crc; 269 | gen->lib = dlopen(lib, RTLD_NOW); 270 | if (gen->lib) { 271 | gen->f = (gen_f) dlsym(gen->lib, sym); 272 | assert(gen->f); 273 | fprintf(stderr, "reloaded %s\n", lib); 274 | return; 275 | } 276 | // else 277 | // printf("%s\n", dlerror()); 278 | 279 | sprintf(src, "z64/rspgen/%x-%x-%x.cpp", crc, pc, len); 280 | FILE * fp = fopen(src, "w"); 281 | 282 | fprintf(fp, 283 | "#include \"rsp.h\"\n" 284 | "\n" 285 | "extern \"C\" {\n" 286 | "int %s() {\n" 287 | "int cond=0;\n", 288 | sym); 289 | 290 | for (i=0; i %x\n", branches[i].start, branches[i].end-4); 294 | for (pc=branches[i].start; cont || delayed; pc = (pc+4)&0xfff) { 295 | UINT32 op = ROPCODE(pc); 296 | char s[128]; 297 | rsp_dasm_one(s, pc, op); 298 | if (cont && OPI(pc).labeled == curvisit) 299 | fprintf(fp, "L%d: ;\n", OPI(pc).label); 300 | //fprintf(fp, "/* %3x\t%s */\n", pc, s); 301 | fprintf(fp, "GENTRACE(\"%3x\t%s\\n\");\n", pc, s); 302 | oldbr = br; 303 | br = 0; 304 | old_delayed = delayed; 305 | delayed = 0; 306 | 307 | if (((pc+4)&0xfff)==branches[i].end) 308 | cont = 0; 309 | 310 | switch (op >> 26) 311 | { 312 | case 0x00: /* SPECIAL */ 313 | { 314 | switch (op & 0x3f) 315 | { 316 | case 0x08: /* JR */ 317 | if (!old_delayed) { 318 | br = 1|8|16; 319 | NOCOND(); 320 | D_JUMP(); 321 | } 322 | break; 323 | case 0x09: /* JALR */ 324 | if (!old_delayed) { 325 | br = 1; 326 | NOCOND(); 327 | D_JUMPL(pc); 328 | } 329 | break; 330 | case 0x0d: /* BREAK */ 331 | br = 2|8; 332 | //delayed = "return 1;"; 333 | has_cond = 0; 334 | break; 335 | } 336 | break; 337 | } 338 | 339 | case 0x01: /* REGIMM */ 340 | { 341 | switch (RTREG) 342 | { 343 | case 0x00: /* BLTZ */ 344 | if (!old_delayed) { 345 | COND(fp, " cond=(INT32)(_RSVAL(0x%x)) < 0;\n", op); 346 | D_JUMP_REL(pc, _SIMM16(op)); 347 | br = 4; 348 | } 349 | break; 350 | case 0x01: /* BGEZ */ 351 | if (!old_delayed) { 352 | COND(fp, " cond=(INT32)(_RSVAL(0x%x)) >= 0;\n", op); 353 | D_JUMP_REL(pc, _SIMM16(op)); 354 | br = 4; 355 | } 356 | break; 357 | case 0x11: /* BGEZAL */ 358 | br = 1; 359 | COND(fp, "cond=(INT32)(_RSVAL(0x%x)) >= 0;\n", op); 360 | D_JUMPL(pc); 361 | break; 362 | } 363 | break; 364 | } 365 | 366 | case 0x02: /* J */ 367 | if (!old_delayed) { 368 | NOCOND(); 369 | D_JUMP_ABS(_UIMM26(op) <<2); 370 | br = 4|8|16; 371 | } 372 | break; 373 | case 0x04: /* BEQ */ 374 | if (!old_delayed) { 375 | COND(fp, " cond=_RSVAL(0x%0x) == _RTVAL(0x%0x);\n", op, op); 376 | D_JUMP_REL(pc, _SIMM16(op)); 377 | br = 4; 378 | } 379 | break; 380 | case 0x05: /* BNE */ 381 | if (!old_delayed) { 382 | COND(fp, " cond=_RSVAL(0x%0x) != _RTVAL(0x%0x);\n", op, op); 383 | D_JUMP_REL(pc, _SIMM16(op)); 384 | br = 4; 385 | } 386 | break; 387 | case 0x06: /* BLEZ */ 388 | if (!old_delayed) { 389 | COND(fp, " cond=(INT32)_RSVAL(0x%0x) <= 0;\n", op); 390 | D_JUMP_REL(pc, _SIMM16(op)); 391 | br = 4; 392 | } 393 | break; 394 | case 0x07: /* BGTZ */ 395 | if (!old_delayed) { 396 | COND(fp, " cond=(INT32)_RSVAL(0x%0x) > 0;\n", op); 397 | D_JUMP_REL(pc, _SIMM16(op)); 398 | br = 4; 399 | } 400 | break; 401 | case 0x03: /* JAL */ 402 | if (!old_delayed) { 403 | br = 1; 404 | NOCOND(); 405 | D_JUMPL(pc); 406 | } 407 | break; 408 | } 409 | 410 | if (!(br&4) && (!old_delayed || !br)) { 411 | if (br && !(br&16)) { 412 | fprintf(fp, "sp_pc = 0x%x;\n", (pc + 4)&0xfff); 413 | } 414 | //fprintf(fp, "rsp_execute_one(0x%x);\n", op); 415 | 416 | 417 | 418 | 419 | 420 | switch (op >> 26) 421 | { 422 | case 0x00: /* SPECIAL */ 423 | { 424 | switch (op & 0x3f) 425 | { 426 | case 0x00: /* SLL */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL << SHIFT;"); break; 427 | case 0x02: /* SRL */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL >> SHIFT; "); break; 428 | case 0x03: /* SRA */ if (RDREG) GEN("RDVAL = (INT32)RTVAL >> SHIFT; "); break; 429 | case 0x04: /* SLLV */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL << (RSVAL & 0x1f); "); break; 430 | case 0x06: /* SRLV */ if (RDREG) GEN("RDVAL = (UINT32)RTVAL >> (RSVAL & 0x1f); "); break; 431 | case 0x07: /* SRAV */ if (RDREG) GEN("RDVAL = (INT32)RTVAL >> (RSVAL & 0x1f); "); break; 432 | case 0x08: /* JR */ GEN("JUMP_PC(RSVAL); "); break; 433 | case 0x09: /* JALR */ GEN("JUMP_PC_L(RSVAL, RDREG); "); break; 434 | case 0x0d: /* BREAK */ 435 | { 436 | GEN( 437 | " \ 438 | *z64_rspinfo.SP_STATUS_REG |= (SP_STATUS_HALT | SP_STATUS_BROKE ); \ 439 | if ((*z64_rspinfo.SP_STATUS_REG & SP_STATUS_INTR_BREAK) != 0 ) { \ 440 | *z64_rspinfo.MI_INTR_REG |= 1; \ 441 | z64_rspinfo.CheckInterrupts(); \ 442 | } \ 443 | rsp.nextpc = ~0; \ 444 | return 1; \ 445 | "); 446 | break; 447 | } 448 | case 0x20: /* ADD */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL + RTVAL); "); break; 449 | case 0x21: /* ADDU */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL + RTVAL); "); break; 450 | case 0x22: /* SUB */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL - RTVAL); "); break; 451 | case 0x23: /* SUBU */ if (RDREG) GEN("RDVAL = (INT32)(RSVAL - RTVAL); "); break; 452 | case 0x24: /* AND */ if (RDREG) GEN("RDVAL = RSVAL & RTVAL; "); break; 453 | case 0x25: /* OR */ if (RDREG) GEN("RDVAL = RSVAL | RTVAL; "); break; 454 | case 0x26: /* XOR */ if (RDREG) GEN("RDVAL = RSVAL ^ RTVAL; "); break; 455 | case 0x27: /* NOR */ if (RDREG) GEN("RDVAL = ~(RSVAL | RTVAL); "); break; 456 | case 0x2a: /* SLT */ if (RDREG) GEN("RDVAL = (INT32)RSVAL < (INT32)RTVAL; "); break; 457 | case 0x2b: /* SLTU */ if (RDREG) GEN("RDVAL = (UINT32)RSVAL < (UINT32)RTVAL; "); break; 458 | default: GEN("unimplemented_opcode(op); "); break; 459 | } 460 | break; 461 | } 462 | 463 | case 0x01: /* REGIMM */ 464 | { 465 | switch (RTREG) 466 | { 467 | case 0x00: /* BLTZ */ GEN("if ((INT32)(RSVAL) < 0) JUMP_REL(SIMM16); "); break; 468 | case 0x01: /* BGEZ */ GEN("if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); "); break; 469 | // VP according to the doc, link is performed even when condition fails 470 | case 0x11: /* BGEZAL */ GEN("LINK(31); if ((INT32)(RSVAL) >= 0) JUMP_REL(SIMM16); "); break; 471 | //case 0x11: /* BGEZAL */ if ((INT32)(RSVAL) >= 0) JUMP_REL_L(SIMM16, 31); break; 472 | default: GEN("unimplemented_opcode(op); "); break; 473 | } 474 | break; 475 | } 476 | 477 | case 0x02: /* J */ GEN("JUMP_ABS(UIMM26); "); break; 478 | case 0x03: /* JAL */ GEN("JUMP_ABS_L(UIMM26, 31); "); break; 479 | case 0x04: /* BEQ */ GEN("if (RSVAL == RTVAL) JUMP_REL(SIMM16); "); break; 480 | case 0x05: /* BNE */ GEN("if (RSVAL != RTVAL) JUMP_REL(SIMM16); "); break; 481 | case 0x06: /* BLEZ */ GEN("if ((INT32)RSVAL <= 0) JUMP_REL(SIMM16); "); break; 482 | case 0x07: /* BGTZ */ GEN("if ((INT32)RSVAL > 0) JUMP_REL(SIMM16); "); break; 483 | case 0x08: /* ADDI */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL + SIMM16); "); break; 484 | case 0x09: /* ADDIU */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL + SIMM16); "); break; 485 | case 0x0a: /* SLTI */ if (RTREG) GEN("RTVAL = (INT32)(RSVAL) < ((INT32)SIMM16); "); break; 486 | case 0x0b: /* SLTIU */ if (RTREG) GEN("RTVAL = (UINT32)(RSVAL) < (UINT32)((INT32)SIMM16); "); break; 487 | case 0x0c: /* ANDI */ if (RTREG) GEN("RTVAL = RSVAL & UIMM16; "); break; 488 | case 0x0d: /* ORI */ if (RTREG) GEN("RTVAL = RSVAL | UIMM16; "); break; 489 | case 0x0e: /* XORI */ if (RTREG) GEN("RTVAL = RSVAL ^ UIMM16; "); break; 490 | case 0x0f: /* LUI */ if (RTREG) GEN("RTVAL = UIMM16 << 16; "); break; 491 | 492 | case 0x10: /* COP0 */ 493 | { 494 | switch ((op >> 21) & 0x1f) 495 | { 496 | case 0x00: /* MFC0 */ if (RTREG) GEN("RTVAL = get_cop0_reg(rsp, RDREG); "); break; 497 | case 0x04: /* MTC0 */ 498 | { 499 | GEN("set_cop0_reg(rsp, RDREG, RTVAL); \n"); 500 | if (RDREG == 0x08/4) { 501 | fprintf(fp, 502 | "if (rsp.inval_gen) {\n" 503 | " rsp.inval_gen = 0;\n" 504 | " sp_pc = 0x%x; \n" 505 | " return 2; \n" 506 | "}\n" 507 | , (pc + 4)&0xfff); 508 | } 509 | break; 510 | } 511 | default: 512 | log(M64MSG_WARNING, "unimplemented cop0 %x (%x)\n", (op >> 21) & 0x1f, op); 513 | break; 514 | } 515 | break; 516 | } 517 | 518 | case 0x12: /* COP2 */ 519 | { 520 | switch ((op >> 21) & 0x1f) 521 | { 522 | case 0x00: /* MFC2 */ 523 | { 524 | // 31 25 20 15 10 6 0 525 | // --------------------------------------------------- 526 | // | 010010 | 00000 | TTTTT | DDDDD | IIII | 0000000 | 527 | // --------------------------------------------------- 528 | // 529 | if (RTREG) GEN("\ 530 | {int el = (op >> 7) & 0xf;\ 531 | UINT16 b1 = VREG_B(VS1REG, (el+0) & 0xf);\ 532 | UINT16 b2 = VREG_B(VS1REG, (el+1) & 0xf);\ 533 | RTVAL = (INT32)(INT16)((b1 << 8) | (b2));}\ 534 | "); 535 | break; 536 | } 537 | case 0x02: /* CFC2 */ 538 | { 539 | // 31 25 20 15 10 0 540 | // ------------------------------------------------ 541 | // | 010010 | 00010 | TTTTT | DDDDD | 00000000000 | 542 | // ------------------------------------------------ 543 | // 544 | 545 | // VP to sign extend or to not sign extend ? 546 | //if (RTREG) RTVAL = (INT16)rsp.flag[RDREG]; 547 | if (RTREG) GEN("RTVAL = rsp.flag[RDREG];"); 548 | break; 549 | } 550 | case 0x04: /* MTC2 */ 551 | { 552 | // 31 25 20 15 10 6 0 553 | // --------------------------------------------------- 554 | // | 010010 | 00100 | TTTTT | DDDDD | IIII | 0000000 | 555 | // --------------------------------------------------- 556 | // 557 | GEN("\ 558 | {int el = (op >> 7) & 0xf;\ 559 | VREG_B(VS1REG, (el+0) & 0xf) = (RTVAL >> 8) & 0xff;\ 560 | VREG_B(VS1REG, (el+1) & 0xf) = (RTVAL >> 0) & 0xff;}\ 561 | "); 562 | break; 563 | } 564 | case 0x06: /* CTC2 */ 565 | { 566 | // 31 25 20 15 10 0 567 | // ------------------------------------------------ 568 | // | 010010 | 00110 | TTTTT | DDDDD | 00000000000 | 569 | // ------------------------------------------------ 570 | // 571 | 572 | GEN("rsp.flag[RDREG] = RTVAL & 0xffff;"); 573 | break; 574 | } 575 | 576 | case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: 577 | case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f: 578 | { 579 | GEN("handle_vector_ops(rsp, op);"); 580 | break; 581 | } 582 | 583 | default: GEN("unimplemented_opcode(op); "); break; 584 | } 585 | break; 586 | } 587 | 588 | case 0x20: /* LB */ if (RTREG) GEN("RTVAL = (INT32)(INT8)READ8(RSVAL + SIMM16); "); break; 589 | case 0x21: /* LH */ if (RTREG) GEN("RTVAL = (INT32)(INT16)READ16(RSVAL + SIMM16); "); break; 590 | case 0x23: /* LW */ if (RTREG) GEN("RTVAL = READ32(RSVAL + SIMM16); "); break; 591 | case 0x24: /* LBU */ if (RTREG) GEN("RTVAL = (UINT8)READ8(RSVAL + SIMM16); "); break; 592 | case 0x25: /* LHU */ if (RTREG) GEN("RTVAL = (UINT16)READ16(RSVAL + SIMM16); "); break; 593 | case 0x28: /* SB */ GEN("WRITE8(RSVAL + SIMM16, RTVAL); "); break; 594 | case 0x29: /* SH */ GEN("WRITE16(RSVAL + SIMM16, RTVAL); "); break; 595 | case 0x2b: /* SW */ GEN("WRITE32(RSVAL + SIMM16, RTVAL); "); break; 596 | case 0x32: /* LWC2 */ GEN("handle_lwc2(rsp, op); "); break; 597 | case 0x3a: /* SWC2 */ GEN("handle_swc2(rsp, op); "); break; 598 | 599 | default: 600 | { 601 | GEN("unimplemented_opcode(op);"); 602 | break; 603 | } 604 | } 605 | 606 | 607 | 608 | 609 | // if (br) { 610 | // if (br & 2) 611 | // fprintf(fp, "return 1;\n"); 612 | // else 613 | // fprintf(fp, "return 0;\n"); 614 | // } 615 | } 616 | if (old_delayed) 617 | fprintf(fp, "%s\n", old_delayed); 618 | } 619 | if (!((/*br|*/oldbr)&8) && ((!oldbr && !(br&2)) || has_cond)) { 620 | fprintf(fp, "/* jumping back to %x */\ngoto L%d;\n", pc, OPI(pc).label); 621 | assert(OPI(pc).labeled == curvisit); 622 | } 623 | } 624 | 625 | fprintf(fp, "}}\n"); 626 | 627 | fclose(fp); 628 | 629 | pid_t pid = fork(); 630 | // SDL redirect these signals, but we need them untouched for waitpid call 631 | signal(17, 0); 632 | signal(11, 0); 633 | if (!pid) { 634 | // char s[128]; 635 | // atexit(0); 636 | // sprintf(s, "gcc -Iz64 -g -shared -O2 %s -o %s", src, lib); 637 | // system(s); 638 | // exit(0); 639 | 640 | //setsid(); 641 | //execl("/usr/bin/gcc", "/usr/bin/gcc", "-Iz64", "-shared", "-g", "-O3", "-fomit-frame-pointer", src, "-o", lib, "-finline-limit=10000", 0); 642 | //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); 643 | //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); 644 | 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); 645 | printf("gnii ??\n"); 646 | exit(0); 647 | } 648 | waitpid(pid, 0, __WALL); 649 | 650 | gen->lib = dlopen(lib, RTLD_NOW); 651 | if (!gen->lib) 652 | log(M64MSG_WARNING, "%s\n", dlerror()); 653 | assert(gen->lib); 654 | log(M64MSG_VERBOSE, "created and loaded %s\n", lib); 655 | gen->f = (gen_f) dlsym(gen->lib, sym); 656 | assert(gen->f); 657 | } 658 | 659 | void rsp_invalidate(int begin, int len) 660 | { 661 | //printf("invalidate %x %x\n", begin, len); 662 | begin = 0; len = 0x1000; 663 | assert(begin+len<=0x1000); 664 | while (len > 0) { 665 | OPI(begin).curgen = 0; 666 | begin += 4; 667 | len -= 4; 668 | } 669 | rsp.inval_gen = 1; 670 | } 671 | 672 | int rsp_jump(int pc) 673 | { 674 | pc &= 0xfff; 675 | sp_pc = pc; 676 | rsp.nextpc = ~0; 677 | opinfo_t * opi = &OPI(pc); 678 | gen_t * gen = opi->curgen; 679 | if (!gen) rsp_gen(pc); 680 | gen = opi->curgen; 681 | GENTRACE("rsp_jump %x (%s)\n", pc, gen->name); 682 | int res = gen->f(rsp); 683 | GENTRACE("r31 %x from %x nextpc %x pc %x res %d (%s)\n", rsp.r[31], pc, rsp.nextpc, sp_pc, res, gen->name); 684 | if (rsp.nextpc != ~0) 685 | { 686 | sp_pc = (rsp.nextpc & 0xfff); 687 | rsp.nextpc = ~0; 688 | } 689 | else 690 | { 691 | //sp_pc = ((sp_pc+4)&0xfff); 692 | } 693 | return res; 694 | } 695 | --------------------------------------------------------------------------------